1. 使用Object类的方法wait()和notify()实现
public class ObjectWait {
public static void main(String[] args) {
Object o = new Object();
Thread t = new Thread(() -> {
System.out.println("线程A被o.wait()阻塞前");
synchronized(o){
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程A被线程B o.notify()唤醒");
},"A");
t.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("线程B唤醒线程A");
synchronized (o){
o.notify();
}
},"B").start();
}
}
- wait和notify需要在同步代码块synchronized中才能使用,获得锁之后才会执行。
- 线程一获得锁,执行到wait方法,释放锁,线程阻塞。线程二随后获得锁,notify方法执行,线程一被唤醒,等待线程二释放锁,线程一获得锁再执行。
2. 使用Lock里面的Condition的await和signal实现唤醒和阻塞
public class ConditionAwait {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
lock.lock();
try {
Util.log("A start");
condition.await();
Util.log("A over");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
lock.unlock();
}).start();
Util.sleep(100);
new Thread(() -> {
lock.lock();
Util.log("B start");
condition.signal();
Util.log("B over");
lock.unlock();
}).start();
}
}
- 借助Lock对象那个里面的newCondition()方法生成一个Condition对象
- 线程一获得锁之后就执行到await方法,线程阻塞,锁释放。
- 线程二获得锁之后执行到signal方法,线程一被唤醒,等线程二释放锁,线程一获得锁后继续执行。
3. 使用LockSupport里面的park和unpark方法实现阻塞和唤醒
public class LockSupportDemo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
Util.log("start");
LockSupport.park();
Util.log("over");
});
t.start();
Util.sleep(100);
new Thread(() -> {
Util.log("start");
LockSupport.unpark(t);
Util.log("over");
}).start();
}
}
- 不需要在同步代码块中执行,不需要锁,能够随时随地的阻塞和唤醒线程,非常灵活
- 线程t执行到park方法就会阻塞,等待另一个线程来unpark(t)来唤醒该线程继续执行。
- 另一个线程执行unpark(t)之后,就和线程t同时继续执行
如何验证执行唤醒之后,两个线程是如何执行的?
分别在阻塞和唤醒的后面加上一个循环
for(int i=0;i<100;i++){
Util.sleep(10);
Util.log("A");
}
辅助工具类Util.java
public class Util {
public static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void log(String msg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()) + " " + Thread.currentThread().getName() + " " + msg);
}
}