Demo15_多线程之间的通信

package test06;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo15_多线程之间的通信 {
public static void main(String[] args) {

    //创建资源对象
        Resource1 r = new Resource1();

// 创建线程任务
Producer1 pro = new Producer1(r);
Consumer2 con = new Consumer2(r);
// 创建线程
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}

}

/*
*多生产多消费
*
*问题:生产了商品没有被消费,同一个产品被消费多次(notify的问题)
*
*被唤醒的进程没有进行判断标记,造成问题一问题
*解决办法: 只要让被唤醒的线程必须判断标记 将if判断标记的方式改为while判断,记住多生产多消费必须是while判断条件
*
*问题二 :改为while之后发现发生了死锁(进程中断)
*生产方唤醒了线程池中生产方的线程(一个唤醒三个等待),本方唤醒本方,发生死锁
*希望本方唤醒对方没有对应方法,所以只能唤醒所有(效率低)。notifyAll
*
*
*JDK1.5提供了新的方法解决多生产多消费问题(接口lock)
*在java.util.concurrent.locks 软件包中提供了相应的解决方案
*lock接口比同步更实用,操作更丰富 lock(); 获取锁 unlock();释放锁
*提供了一个更加面向对象的锁,在该锁中提供了更多的显示锁的操作,替代同步方法。
*
*将程序升级到JDK1.5 将同步改写为lock
*
*已经将旧锁替换成新锁,那么锁上的将使其方法(wait,notify,notifyAll)也应该替换成新锁上的监视器方法
*而JDK1.5将这些原有的监视器方法封装到condition对象上
*想要获取监视器方法先获取condition对象
*
*condition对象的出现其实就是替代了object中的监视器方法
*await();
*signal();
*singalAll();
*
*将所有的监视器方法替换成了condition对象
*功能和之前的程序是一样的仅仅是使用了新的对象改了写法,效率问题没有解决
*
*希望本方可以唤醒对方的一个,之前的程序通过两个锁的嵌套完成,但是容易引发死锁
*新程序就可以解决这个问题,因为只有一个锁(一个锁上挂多个监视器对象)
*
*/
//描述生产者 属性:名称 编号 行为: 对名称进行赋值 获取商品
class Resource1
{
private String name ;
private int count = 1;
private Lock lock = new ReentrantLock();//用全名,加一个import 包名.类名;
// 定义标记
//获取锁上的condition对象 为了解决本方唤醒对方的问题,我们可以在一个锁上创建两个监视器对象
private Condition con = lock.newCondition();//负责消费
private Condition pro = lock.newCondition();//负责生产
private boolean flag = false ;

    public void set(String name) //t1   t2
    {
        lock.lock();//获取锁
        try
        {
        while(flag) //标记   判断多次
            try {pro.await();} catch (InterruptedException e) {}//t1等待  t2等待

// 给成员变量赋值并加上编号
this.name = name + count ;
// 编号自增
count++ ;
System.out.println(Thread.currentThread().getName()+”…生产者…”+this.name);
flag = true ;//将标记改为真
//唤醒消费者
con.signal();
}
finally{lock.unlock();}//一定要执行

    }
    public void out() //t3   t4
    {
        lock.lock();
        try{
        while(!flag)
            try {con.await();} catch (InterruptedException e) {} //t3等待   t4等待
        System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
        flag = false;//将标记改为假
        //唤醒生产者
        pro.signal();
        }
        finally{lock.unlock();}
    }
}
//描述生产者 处理资源
class Producer1 implements Runnable
{
    private Resource1 r ;
    //生产者一初始化就有资源,需要将资源传递到构造函数中
    Producer1(Resource1 r)
    {
        this.r = r ;
    }
    public void run()
    {
        while(true){
        r.set("mianbao");}
    }
}
//描述消费者 处理资源
class Consumer2 implements Runnable
{
    private Resource1 r ;
    //消费者一初始化就有资源,需要将资源传递到构造函数中
    Consumer2(Resource1 r)
    {
        this.r = r ;
    }
    public void run()
    {
        while(true)
        {
            r.out();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/mingxu_W/article/details/81742546