线程通信的概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程之间的通信就成为整体的比用方法之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会是开发人员对线程任务在处理的过程中进行有效的把控与监督。
使用wait和notify方法实现线程之间的通信,(注意这两个方法都是object的类的方法,换句话说java为所有的对象都提供了这两个方法)。
wait和notify必须配合synchronized关键字使用,
wait方法释放锁,notify方法不释放锁。
package com.thread.mythread.conn006;
import java.util.ArrayList;
import java.util.List;
public class AddToList {
private volatile static List list = new ArrayList();
public void add(){
list.add("mmm");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final AddToList list1 = new AddToList();
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i <10; i++){
list1.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
public void run() {
while(true){
if(list1.size() == 5){
System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");
throw new RuntimeException();
}
}
}
}, "t2");
t1.start();
t2.start();
}
}
打印结果:
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread “t2” java.lang.RuntimeException
at com.thread.mythread.conn006.AddToList$2.run(AddToList.java:42)
at java.lang.Thread.run(Thread.java:748)
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
上面是原始的通信,下面使用wait和notify实现:
package com.thread.mythread.conn006;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class AddToList2 {
private volatile static List list = new ArrayList();
public void add(){
list.add("mmm");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final AddToList2 list2 = new AddToList2();
//创建一个对象,用于添加锁
final Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
synchronized (lock) {
System.out.println("t1启动..");
for(int i = 0; i <10; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
if(list2.size() == 5){
System.out.println("已经发出通知..");
lock.notify();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
System.out.println("t2启动..");
if(list2.size() != 5){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
}
}
}, "t2");
t2.start();//t2先执行,先获取lock的锁
t1.start();
}
}
打印结果:
t2启动..
t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
Exception in thread “t2” 当前线程:t2收到通知线程停止..
java.lang.RuntimeException
at com.thread.mythread.conn006.AddToList2$2.run(AddToList2.java:60)
at java.lang.Thread.run(Thread.java:748)
执行流程:
首先t2先执行,先获取到对象锁lock,当list的长度不为5的时候,lock被释放掉(wait释放锁),lock被t1获取,t1开始执行往list添加元素的操作。当添加的元素个数达到5个的时候,执行notify操作唤醒t2的wait操作,由于notify不释放锁,所以t1无法接受到t1的唤醒通知,直到t1执行完成,t2才被唤醒,接着执行下面的操作。
使用wait和nofity的方式有一种弊端,那就是通信不及时。
对代码再一次做修改,使用CountDownLatch对象。
package com.thread.mythread.conn006;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class AddToList2 {
private volatile static List list = new ArrayList();
public void add(){
list.add("mmm");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final AddToList2 list2 = new AddToList2();
// final Object lock = new Object();
final CountDownLatch countDownLatch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
// synchronized (lock) {
System.out.println("t1启动..");
for(int i = 0; i <10; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
if(list2.size() == 5){
System.out.println("已经发出通知..");
// lock.notify();
countDownLatch.countDown();
}
// }
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
public void run() {
// synchronized (lock) {
System.out.println("t2启动..");
if(list2.size() != 5){
try {
// lock.wait();
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
}
// }
}, "t2");
t2.start();//t2先执行
t1.start();
}
}
执行结果如下:
t2启动..
t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
当前线程:t2收到通知线程停止..
当前线程:t1添加了一个元素..
Exception in thread “t2” java.lang.RuntimeException
at com.thread.mythread.conn006.AddToList2$2.run(AddToList2.java:60)
at java.lang.Thread.run(Thread.java:748)
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..