一、基本认识
在讲解java线程之间的问题时,我们先想一下,为什么需要线程之间的通信呢?我们举一个例子:
愚公门前有座大山,想要移走,可是评价自己的力量肯定不够呀,于是叫来了一伙人,一块把这座山移走。
以上这个简单的案例就能够表达我们的意思,也就是需要合作办成某件事。在java中,我们想要完成某个功能,一个线程完成不了,这时候就需要两个或者是多个线程一块来完成了,多个线程一块合作这时候就需要交流,也就是通信了。
通信的方式很多,比如说共享内存、管道、mutex等等各种方式,不管是那种方式都是为了完成功能而已。
另外还有一个需要注意的问题,那就是什么是进程间通信?我们同样举一个例子。
有两个国家,国家内部之间的交流就是线程间通信,两个国家之间的交流就是进程间通信。
下面我们就来看看如何进行通信。
二、单线程间通信实现
java解决单线程之间的通信很简单,大致上有三种,我们依次来分析实现一下。这里要完成一个功能,那就是生产者和消费者模型。假设我们想要完成的功能描述如下:
工厂生产完了东西之后,通知消费者消费,在生产出来之前,消费者等待。我们直接看实现方法。
public class ProduceAndConsumerModel { private int a = 0; private Object lock = new Object(); public static void main(String[] args) { //待验证 } // 生产过程 public void produce() { synchronized (lock) { for (int i = 0; i < 10; i++) { System.out.println("生产者生产产品:" + (a++)); } } } // 消费过程 public void consume() { synchronized (lock) { for (int i = 0; i < 10; i++) { System.out.println("消费者消费产品:" + (a)); } } } }
上面的这个生产消费过程看起来完全没毛病,我们就写一下main方法中测试一下:
public class ProduceAndConsumerModel { public static void main(String[] args) { ProduceAndConsumerModel model = new ProduceAndConsumerModel(); // 生产线程一直不停的生产 new Thread() { public void run() { model.produce(); }; }.start(); // 消费线程一直不停的消费 new Thread() { public void run() { model.consume(); }; }.start(); } }
也就是说我们开启两个线程,一个用于生产,一个用于消费,没毛病吧。那我们就运行一下,看看结果。
我们一下子把所有的全部生产出来了,但是消费的时候消费了最后一个而且还是重复消费的。这就有问题了,我们明明想要的就是生产一个消费一个,这时候怎么办呢?这就用到了我们的等待通知模型。
public class ProduceAndConsumerModel { private int a = 0; private Object lock = new Object(); // 关键点:添加一个标志,表示是否已经生产了 private volatile boolean isProduced = false; // 生产过程 public void produce() throws InterruptedException { synchronized (lock) { // 如果已经生产了,那就等消费了再生产 if (isProduced) { lock.wait(); } else {// 没有生产,那就生产一个,并通知消费者去消费 System.out.println("生产者生产一个产品:" + (a++)); lock.notify(); } } }// 方法结束 // 消费过程 public void consume() throws InterruptedException { synchronized (lock) { // 如果有产品,那就消费,并通知生产者可以继续生产了。 if (isProduced) { System.out.println("消费者消费一个产品:" + (a)); lock.notify(); isProduced = false; } else {// 如果没有产品,那就等待一会 lock.wait(); } } }// 方法结束 }
现在我们再来测试一下:
public class ProduceAndConsumerModel { public static void main(String[] args) { ProduceAndConsumerModel model = new ProduceAndConsumerModel(); // 生产线程一直不停的生产 new Thread() { public void run() { while (true) { model.produce(); } }; }.start(); // 消费线程一直不停的消费 new Thread() { public void run() { while (true) { model.consume(); } }; }.start(); } }
我们再看一下测试结果吧。
以上就是单线程之间通信最简单的解决方法。当然了单线程的通信肯定是不能满足我们的日常需求的。而且对于上述问题我们还有很多其他的方式可以解决。这篇文章只是起到一个抛砖引玉的作用。