JAVA并发编程学习笔记05-线程通信
两个线程之间的通信(保护性暂停)
针对两个线程实现信息通信,可以通过中间对象实现。
@Slf4j
public class Test03 {
public static void main(String[] args) throws InterruptedException {
GuardedObject guardedObject = new GuardedObject();
Thread t1 = new Thread(() -> {
log.info("start get");
Object obj = guardedObject.get();
log.info("obj:{}", obj);
log.info("end get");
}, "t1");
Thread t2 = new Thread(() -> {
log.info("start set");
guardedObject.set("你好");
log.info("end set");
}, "t2");
t1.start();
Thread.sleep(2000);
t2.start();
}
}
class GuardedObject {
private Object obj;
public synchronized Object get() {
while (obj == null) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return obj;
}
public synchronized void set(Object obj) {
this.obj = obj;
this.notifyAll();
}
}
从打印结果看,线程1在get后暂停,然后当线程2将信息写入后,线程1立马获取到了该信息,从而实现了线程的通信。
思路类似join()方法,区别在于,join必须等到线程执行结束才会触发,而保护性暂停则更灵活。
多个线程之间的通信(消息队列)
@Slf4j
public class Test04 {
public static void main(String[] args) throws InterruptedException {
MessageQueue queue = new MessageQueue(2);
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
log.info("start set");
queue.put("你好");
log.info("end set");
}).start();
}
Thread.sleep(2000);
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
log.info("start get");
Object obj = queue.take();
log.info("obj:{}", obj);
log.info("end get");
}, "t" + i).start();
}
}
}
class MessageQueue {
public MessageQueue(int size) {
this.size = size;
}
private int size;
private ArrayDeque<Object> deque = new ArrayDeque<>();
public synchronized Object take() {
// 当没有消息时,进入等待
while (deque.isEmpty()) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object msg = deque.remove();
// 唤醒因为消息满了而等待的线程
this.notifyAll();
return msg;
}
public synchronized void put(Object obj) {
// 当队列消息满了,则等待
if (deque.size() >= size) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
deque.add(obj);
// 唤醒等待获取的线程
this.notifyAll();
}
可以看到,由于队列size=2,故第三次set处于等待状态,当2秒后get触发了,消息被消费,才set成功。