最新新闻:

线程修改对象的值时方法

时间: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;

生产为消费创造动力_生产 消费 关系_c#生产消费者问题

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 释放锁,然后才能继续沿着阻塞的线程继续。开始执行的位置。

流程图如下:

声明:文章仅代表原作者观点,不代表本站立场;如有侵权、违规,可直接反馈本站,我们将会作修改或删除处理。

猜您喜欢

图文推荐

热点排行

精彩文章

热门推荐