多线程
概念
-
同步
先做1,1做完了再做2
-
异步
两件事可以一起做
快速入门
-
Thread.sleep()
在当前线程睡眠,单位为毫秒
-
Thread::start
启动线程
-
Thread::run
线程在执行时,要运行的代码
-
SecondThread.java
package com.futureweaver.multithread;
public class SecondThread extends Thread {
@Override
public void run() {
try {
while (true) {
System.out.println("第二个线程的代码");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("第二个线程退出了...");
}
}
}
- ThreadPractice.java
package com.futureweaver.multithread;
public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
Thread thread = new SecondThread();
thread.start();while (true) { System.out.println("主线程里面的代码"); // InterruptedException异常为别人想要关闭此线程 // 在运行此代码时,会收到一个异常 // 抓此异常,目的是为了释放掉自己所占用的资源 // 抛此异常,目的是不做任何处理,直接退出程序 // 当前线程睡眠多少毫秒 Thread.sleep(2000); } }
}
使用时的注意事项
每创建一个线程,都要有名字
Thread结合Runnable的用法
在使用线程时,应注意关注点分离,Thread只用于处理创建线程、在线程里执行过程等等的功能 Runnable只关注要干什么 关注点分离的好处在于,无需重度重写父类的方法,就可以直接用
- SecondRunnable.java
package com.futureweaver.multithread;
public class SecondRunnable implements Runnable {
@Override
public void run() {
try {
while (true) {
System.out.println("这是一个Thread结合Runnable要执行的代码");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("线程退出...");
}
}
}
- Thread2Practice.java
package com.futureweaver.multithread;
// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
SecondRunnable secondRunnable = new SecondRunnable();
Thread thread = new Thread(secondRunnable, "thread and runnable ...");
thread.start();while (true) { System.out.println("主线程代码"); Thread.sleep(2000); } }
}
Runnable的匿名内部类的用法
- Thread2Practice.java
package com.futureweaver.multithread;
// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
Runnable secondRunnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("second runnable里的过程");
Thread.sleep(1500);
}
} catch (InterruptedException e) {
System.out.println("线程退出了");
}
}
};
Thread thread = new Thread(secondRunnable, "thread and runnable ...");
thread.start();while (true) { System.out.println("主线程代码"); Thread.sleep(2000); } }
}
Runnable的lambda表达式写法【重点】
- Thread2Practice.java
package com.futureweaver.multithread;
// 多线程的第二种用法
// Thread结合Runnable使用public class Thread2Practice {
public static void main(String[] args) throws InterruptedException {
// 匿名内部类,缺什么方法,就重写什么方法即可
// lambda表达式必须是函数式接口// public void run() {...} // public是能够智能识别的 // void是能够智能识别 // ()说明的是函数式接口当中的函数没有任何参数,假设有参数,参数类型都不用写,因为可以智能识别 // ->用于分隔参数和函数体/方法体 // {}方法体 // 方法体内,如果函数式接口当中的函数需要返回值,那就写return语句 // 如果返回值类型为void,那就不写return语写 Thread thread = new Thread(() -> { try { while (true) { System.out.println("second runnable里的过程"); Thread.sleep(1500); } } catch (InterruptedException e) { System.out.println("线程退出了"); } }, "thread and runnable ..."); thread.start(); while (true) { System.out.println("主线程代码"); Thread.sleep(2000); } }
}
注意
线程同步操作演示
- SecondRunnable.java
package com.futureweaver.threadsync;
import java.util.ArrayList;
import java.util.List;public class SecondRunnable implements Runnable {
private List<String> list;public SecondRunnable(List<String> list) { this.list = list; } @Override public void run() { try { for (int i = 20000; i < 21000; i++) { Thread.sleep(1); add(list, Integer.toString(i)); } } catch (InterruptedException e) { throw new RuntimeException(e); } } // syncrhonized关键字能够保证在操作此list时,不会发生资源争抢问题 public static synchronized void add(List<String> list, String str) { // 开始 list.add(str); // 结束 }
}
- ThreadPractice.java
package com.futureweaver.threadsync;
import java.util.ArrayList;
import java.util.List;public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
SecondRunnable secondRunnable = new SecondRunnable(list);
Thread thread = new Thread(secondRunnable);
thread.start();for (int i = 0; i < 10000; i++) { Thread.sleep(1); String s = Integer.toString(i); SecondRunnable.add(list, s); } Thread.sleep(5000); System.out.println(list); }
}
死锁问题
所谓死锁问题,就是在等待一把永远也解不开的锁
死锁案例1
加锁后出现异常,导致锁无法解开
- SecondRunnable.java
package com.futureweaver.threadsync;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.reentrantlock;public class SecondRunnable implements Runnable {
private List<String> list;// 注意,如果多个线程同时操作某个资源 // 那么想要用Lock加线程同步,必须要保证这几个线程用的是同一把锁 public static Lock lock = new reentrantlock(); public SecondRunnable(List<String> list) { this.list = list; } @Override public void run() { try { for (int i = 20000; i < 21000; i++) { Thread.sleep(1); add(list, Integer.toString(i)); } } catch (InterruptedException e) { throw new RuntimeException(e); } } public static void add(List<String> list, String str) { // 将这一把锁上锁 lock.lock(); // 开始 list.add(str); // 结束 list.get(30000); // 将这一把锁解锁 lock.unlock(); }
}
- ThreadPractice.java
package com.futureweaver.threadsync;
import java.util.ArrayList;
import java.util.List;public class ThreadPractice {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
SecondRunnable secondRunnable = new SecondRunnable(list);
Thread thread = new Thread(secondRunnable);
thread.start();for (int i = 0; i < 10000; i++) { Thread.sleep(1); String s = Integer.toString(i); SecondRunnable.add(list, s); } Thread.sleep(5000); System.out.println(list); }
}
死锁案例二
小明锁了A,等待B。同时B被小红锁上,等待A
- XiaoHong.java
package com.futureweaver.threadsync;
import java.util.concurrent.locks.Lock;
public class XiaoHong implements Runnable {
private Lock left;
private Lock right;public XiaoHong(Lock left, Lock right) { this.left = left; this.right = right; } @Override public void run() { right.lock(); System.out.println("小红拿到第二根筷子"); left.lock(); System.out.println("小红拿到第一根筷子"); System.out.println("吃饭"); left.unlock(); right.unlock(); }
}
- XiaoMing.java
package com.futureweaver.threadsync;
import java.util.concurrent.locks.Lock;
public class XiaoMing implements Runnable {
private Lock left;
private Lock right;public XiaoMing(Lock left, Lock right) { this.left = left; this.right = right; } @Override public void run() { left.lock(); System.out.println("小明拿到了第一根筷子"); right.lock(); System.out.println("小明拿到了第二根筷子"); System.out.println("吃饭"); right.unlock(); left.unlock(); }
}
- DoubleLockDeadPractice.java
package com.futureweaver.threadsync;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.reentrantlock;public class DoubleLockDeadPractice {
public static void main(String[] args) {
Lock left = new reentrantlock();
Lock right = new reentrantlock();Thread xiaohong = new Thread(new XiaoHong(left, right)); Thread xiaoming = new Thread(new XiaoMing(left, right)); xiaohong.start(); xiaoming.start(); }
}