时间:2022-09-06 12:01:57来源:网络整理
线程之间的通信,也称为线程同步,是指当一个线程修改一个对象的值时,另一个线程可以感知到该值的变化并进行相应的操作。
实现线程间通信的方法有:
1.易失性修改的共享变量
2.通过等待和通知机制
3.Thread.Join 方法
4.使用同步关键字
5.Condition.await/信号方法
Java提供了(wait/notify)等待/通知机制来实现多线程间的协同处理,即控制线程间的等待和唤醒。
wait() 方法使当前线程进入阻塞状态并释放持有的锁。
notify()方法,唤醒下一个处于阻塞状态的线程
notifyAll() 方法唤醒所有阻塞的线程。
线程的通信(wait/notify)等待/通知机制是指一个线程A调用对象O的wait()方法进入等待状态,而另一个线程B调用notify()或notifyAll()在对象 O ) 方法中,线程 A 在收到通知后从对象 O 的 wait() 方法中返回,然后执行后续操作。上面两个线程通过对象O完成交互,对象上的wait()和notify/notifyAll()的关系就像一个开关信号,用来完成等待方和通知方的交互。
1 生产者/消费者问题
Producer/Consumer 是一种经典的线程通信和协作机制。接下来,我们设计一个简单的模型。
制作人:
public class Product implements Runnable {
private Queue msg;
private int maxSize;
public Product(Queue msg, int maxSize) {
this.msg = msg;
this.maxSize = maxSize;
}
@Override
public void run() {
int i=0;
while (true) {
synchronized (msg) {
while (msg.size() == maxSize) {
//生产者满了
try {
msg.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产...");
msg.add("生产消息"+i);
msg.notify();
msg.notifyAll();
}
}
}
}
Producer代表一个生产者线程,它定义了一个共享对象msg,然后在run()方法中实现如下逻辑:
从代码中可以看出,wait()和notify()方法必须写在同步代码块中。至于原因c#生产消费者问题,我们稍后再分析。
消费者:
public class Consumer implements Runnable {
private Queuemsg;
private int maxSize;
public Consumer(Queue msg, int maxSize) {
this.msg = msg;
this.maxSize = maxSize;
}
@Override
public void run() {
while (true){
synchronized (msg){
//消费者空了
while (msg.isEmpty()){
try {
msg.wait();//阻塞当前队列
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费消息"+msg.remove());
msg.notify();//唤醒处于等待状态的生产者
}
}
}
}
Consumer代表一个消费者线程,同样使用共享对象msg,然后在run()方法中实现如下逻辑:
写一段测试代码,main方法:
public class TestMain {
public static void main(String[] args) {
Queuequeue=new LinkedList<>();
int maxSize=2;
Product product=new Product(queue,maxSize);
Consumer consumer=new Consumer(queue,maxSize);
Thread t1=new Thread(product);
Thread t2=new Thread(consumer);
t1.start();
t2.start();
}
}
生产者先生产数据,然后唤醒消费者线程。产生两条数据后,发现队列已满。此时生产者线程被wait()方法阻塞。消费者线程开始运行。如果发现队列中的元素不为空,则消费数据并唤醒生产者线程。如果消费者发现队列为空,则阻塞消费者线程。
生产者/消费者如果深度设计的话可能会很复杂,比如如果有多个消费者或者生产者怎么设计等等。
2 图形生产者/消费者
上述生产者/消费者模型的执行过程是怎样的?
我们使用队列作为双方的共享队列,生产者和消费者都会对共享队列进行读写操作。因此,为了保证原子性,生产者和消费者线程必须对共享队列加锁c#生产消费者问题,只有竞争锁资源的线程才能加锁,也就是操作队列的数据。
假设生产者抢到了锁,就开始往队列中添加数据,直到队列满了发生阻塞,也就是消费者应该消费数据。代码中,在synchronized中调用了生产者的wait()方法,此时锁并没有被释放,那么如果获取不到同步锁,消费者该怎么办呢?实际上,线程调用wait()方法后,当前的同步锁就会被释放。由于此时Consumer正在同步的同步队列中等待,一旦锁被释放,Producer就可以唤醒Consumer线程。 Consumer被唤醒后,需要竞争锁资源。如果成功,它将消耗数据。
消费者在消费完一条数据后会调用notify()方法。该方法只唤醒处于阻塞状态的线程。由于 Consumer 还没有释放锁,因此被唤醒的 Producer 需要等待 Consumer 释放锁,然后才能继续沿着阻塞的线程继续。开始执行的位置。
流程图如下:
声明:文章仅代表原作者观点,不代表本站立场;如有侵权、违规,可直接反馈本站,我们将会作修改或删除处理。
图文推荐
2022-09-06 12:01:57
2022-09-06 10:10:37
2022-09-06 09:10:06
2022-09-06 09:03:48
2022-09-06 08:10:08
2022-09-05 18:10:03
热点排行
精彩文章
2022-09-06 09:10:42
2022-09-06 09:10:20
2022-09-06 08:10:20
2022-09-05 16:10:49
2022-09-05 13:10:16
2022-09-05 09:02:44
热门推荐