1、为什么要处理线程间通信 :
当我们需要多个线程共同协作完成一件任务,并且希望他们有规律的执行,那么此时就需要线程之间进行通信。为了能达到此种目的我们需要引入一个机制——等待唤醒机制。
2、 等待唤醒机制
这是多个线程间的一种协作机制。
就是在一个线程进行了规定操作后 ,就进入等待状态 (wait() ), 等待其他线程执行完他们的指定代码过后 再将 其唤醒 (notify() );在有多个线程进行等待时, 如果需要 ,可以使用 notifyAll()来唤醒所有的等待线程。
2.1 wait() 与notify() 和notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源并等待
- 在当前线程中调用方法: 对象名.wait()
- 使当前线程进入等待(某对象)状态,直到另一线程对该对象发出notify (或notifyAll) 为止。
- 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
- 调用此方法后,当前线程将释放对象监控权,然后进入等待
- 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
notify()/notifyAll()
-
在当前线程中调用方法: 对象名.notify() 或者 对象名.notifyAll()
-
功能:唤醒等待该对象监控权的一个或者所有线程。
-
调用方法的必要条件:当前线程必须调用了wait()
2.2 面试题:
编写一个程序,开启三个线程,这三个线程的名字分别为A,B,C 每个线程将自己的名字打印10次,交替打印,如ABCABCABCABCABCABC…
方法1:jdk1.5 前:wait()、notify()
代码:
//两个线程交替执行
public class TestABABAB {
public static int flag = 1;
public static void main(String[] args) {
// 1、线程通信,需要wait notify 但是这两个必须和synchronize共同使用
Object objA = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objA) {
for (int i = 0; i < 10; i++) {
while (flag != 1) {
try {
objA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 2;
objA.notifyAll();
}
}
}
}, "A").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objA) {
for (int i = 0; i < 10; i++) {
while (flag != 2) {
try {
objA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 3;
objA.notifyAll();
}
}
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objA) {
for (int i = 0; i < 10; i++) {
while (flag != 3) {
try {
objA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 1;
objA.notifyAll();
}
}
}
}, "C").start();
}
}
执行结果:
jdk1.5后 lock() 和condition
Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用 法上与使Object.wait 访问的隐式监视器类似,但提供了更强大的 功能。需要特别指出的是,单个 Lock 可能与多个 Condition 对象关 联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版 本中的不同。
在 Condition 对象中,与 wait、notify 和 notifyAll 方法对应的分别是 await、signal 和 signalAll。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
代码:
public class TestABABAB1 {
public static int flag = 1;
public static void main(String[] args) {
// 1、线程通信,需要wait notify 但是这两个必须和synchronize共同使用
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (flag != 2) {
try {
conditionB.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 3;
conditionC.signal();
} finally {
lock.unlock();
}
}
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (flag != 3) {
try {
conditionC.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 1;
conditionA.signal();
} finally {
lock.unlock();
}
}
}
}, "C").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
if (flag != 1) {
try {
conditionA.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
flag = 2;
conditionB.signal();
} finally {
lock.unlock();
}
}
}
}, "A").start();
}
}
下面给一个链接:https://www.jianshu.com/p/40078ed436b4
下面是这道题目的四种优雅写法。