线程通信
wait()与notify()
首先考虑下面的情景,一个线程必须要等另外一个线程执行完才能继续执行,可以设置一个变量,第二个线程一直监控它,当第一个线程执行完后修改这个变量的值,第二个线程监控到值发生了改变然后继续执行,如下代码
public class Demo {
private volatile boolean signal = false;
public static void main(String[] args) {
Demo d = new Demo();
// 第一个线程
new Thread(() -> {
System.out.println("准备数据。。。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
d.signal = true;
}).start();
// 第二个线程
new Thread(() -> {
while (!d.signal) {
// 这里防止一直循环 稍微休眠
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("模拟代码执行。。。。");
}).start();
}
}
上面的方式通过while循环去阻塞,会非常的耗费资源,那么有没有更简单的方式呢?答案是有的
在Object对象中,有两个方法,wait()跟notify(),它们的作用就是用来阻塞线程跟唤醒线程
首先需要了解使用它们的条件:
- 在同步代码块中使用
- 使用的必须是同步代码块对象的wait()与notify()方法
public class Demo {
public static void main(String[] args) {
Demo d = new Demo();
// 第一个线程
new Thread(() -> {
System.out.println("准备数据。。。。。");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("准备数据完成。。。");
synchronized (d) {
d.notify();
}
}).start();
for (int i = 0; i < 2; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread() + "等待代码执行。。。");
synchronized (d) {
try {
d.wait(); // wait会释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + "模拟代码执行。。。。");
}).start();
}
}
}
关于wait与notify的特点
- wait()在执行后会释放掉synchronized锁,因此使得上面的代码执行起来没有问题
- 执行notify()方法会加锁
- notify()只会随机唤醒一个被等待的线程,如果需要全部唤醒,则必须执行notifyAll()方法
Condition条件锁
Condition接口中的await()跟signal()方法的作用与wait()跟notify()的一致
Condition使用实例:
public class ConditionTest {
private Lock lock = new ReentrantLock();
private Condition a = lock.newCondition();
private Condition b = lock.newCondition();
public void a() {
while (true) {
lock.lock();
try {
a.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("a");
b.signal();
lock.unlock();
}
}
public void b() {
while (true) {
lock.lock();
a.signal();
System.out.println("b");
try {
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
}
public static void main(String[] args) {
ConditionTest ct = new ConditionTest();
// 要求:a b c方法有序执行
new Thread(ct::a).start();
new Thread(ct::b).start();
}
}
通过上面的实例,可以知道await()跟signal()也是需要使用锁的。