生命周期
创建线程
class MyThread extends Thread{@Overridepublic void run(){ System.out.println("Hello World"); }
}class MyRunnable implements Runnable{@Overridepublic void run() { System.out.println("Hello World"); }
}public class Test1 {public static void main(String[] args) {// 匿名内部类new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Hello World");}}).start();// Threadnew MyThread().start(); // Runnable Runnable myRunnable = new MyRunnable();Thread t1 = new Thread(myRunnable);Thread t2 = new Thread(myRunnable);t1.start();t2.start();}
}
常用方法
方法 | 作用 | 描述 |
---|---|---|
Thread() | 创建线程 | 构造方法,有不同的构造方法,能多种形式创建线程 |
start() | 启动线程 | jvm 自动调用 run 方法 |
run() | 线程的主体方法,定义线程的执行逻辑 | 不需要手动调用,jvm 自动调用 |
setName(String) | getName() | 设置和获取线程名称 | |
join() | join(millis) | 线程插队 | 在 a 线程的 run 方法中调用 b.join,那么 b 执行完才会执行 a |
sleep(long millis) | 线程休眠 | 让出 CPU ,不让出锁,时间到了再次抢夺 CPU(休眠期不会抢) |
yield() | 线程让步 | 让出 CPU ,不让出锁,可能让出 CPU 时间片后立马又被分配到了 |
currentThread() | 获取当前线程 |
线程等待和唤醒
- wait:让出 cpu 时间片和 锁,程序走到这里立马暂停,既然要让处锁,所以必须先持有锁,所以必须用在 synchronized 中
- notify:唤醒正在等待 同一个锁 的线程,不是随便唤醒线程,而是等待同一个锁的线程,所以也必须用在 synchronized 中
notify 不会释放锁,要等到方法执行完才会释放锁
public class WaitNotifyExample {private final Object lock = new Object();private boolean condition = false;public void waitForCondition() throws InterruptedException {synchronized (lock) { while (!condition) { // synchronized 中的判断不能用 if 要用 whileSystem.out.println("让出 CPU 和锁.....");lock.wait(); // 等待条件为真}System.out.println("又抢到锁和分到 cpu 时间片...");}}public void setConditionTrue() {synchronized (lock) {condition = true;lock.notify(); // 唤醒一个等待线程(notify 不释放锁,但是这已是方法最后一行,方法结束会释放锁)// lock.notifyAll(); // 或者唤醒所有等待线程}}public static void main(String[] args) throws InterruptedException {WaitNotifyExample example = new WaitNotifyExample();Runnable waitTask = () -> {try {example.waitForCondition();} catch (InterruptedException e) {e.printStackTrace();}};Thread thread1 = new Thread(waitTask);thread1.start();Thread.sleep(2000); // 等待2秒钟// 在主线程中设置条件为true,唤醒等待线程example.setConditionTrue();}
}
线程安全 synchronized
- 同步方法
- 非静态同步方法,锁的是 this,调用哪个对象的同步方法,锁的就是谁
- 静态同步方法,锁的是类,全局唯一
- 同步块,可以指定锁对象,可以是一个对象,也可以是一个 Class,如果是 this ,和非静态同步方法一致,锁的是调用者
// 非静态同步方法
public synchronized void method(){}
a.method() // 锁的是 a// 静态同步方法
public synchronized static void method() {}
b.method() // 锁的是 method 所在的类// 同步代码块
public void method(){synchronized(this){} // 可以指定为某个对象或者 Class
}
c.method() // 锁的是 c
死锁
面试官:你告诉我什么是死锁我就录取你。候选人:你录取我我就告诉你什么是死锁
往往都是嵌套的 synchronized 导致
// 多运行几遍,如果效果不明显就两个线程获取第一把锁后分别 sleep 一会(两个线程获取的是不同的锁,第一次肯定都能获取)
public class DeadLockDemo { // 两个锁private static String A="A"; private static String B="B"; public static void main(String[] args){ // 线程1new Thread(new Runnable(){ @Override public void run(){ synchronized(A){ // 拿到 A 才进入synchronized(B){ // 拿到 B 才进入(这时要同时具有 A 和 B)System.out.println("AB"); } } } });// 线程2new Thread(new Runnable(){ @Override public void run(){ synchronized(B){ synchronized(A){ // 这时要同时具有 A 和 BSystem.out.println("BA"); } } } });}
}