多线程生产者与消费者模式的几种写法

在生产者与消费者关系中,存在着一个多线程操作同一个资源的情况,在这里我使用了int作为资源类型,而++操作不是线程安全的,因此会导致数据错误。而为了保证线程执行的有序性,急需要对方法进行加锁。

一:使用synchronized锁


//生产者与消费者
public class ProductCustomer {
    public static void main(String[] args) {
        Data d =new Data();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                d.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadA  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                d.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadB  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                d.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadC  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                d.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadD  ").start();

    }
}

class  Data{
private int data = 10;

public synchronized void increment() throws InterruptedException {
    //这里要使用while而不能是if,因为if只会判断一次,一旦多个线程同时操作则会出错
    //因此可能会导致wait的虚假唤醒
    while (data!=10){
    this.wait(); //等待
    }
    data++;
    System.out.println(Thread.currentThread().getName()+"=>"+data);
    //通知线程++完毕
    this.notifyAll();
}

public synchronized void decrement() throws InterruptedException {
        while(data==10){
            this.wait(); //等待
        }
        data--;
        System.out.println(Thread.currentThread().getName()+"=>"+data);
        //通知线程--完毕
        this.notifyAll();
    }

}




二:使用Lock锁


//JUC生产者与消费者
public class NewProductCustomer {
    public static void main(String[] args) {
        Customer c = new Customer();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                c.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadA  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                c.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadB  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                c.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadC  ").start();
        new Thread(()->{for(int i=1;i<=10;i++) {
            try {
                c.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        },"threadD  ").start();

    }
}

class Customer{
    private int datas = 10;
    Lock lock = new ReentrantLock();//声明锁
    Condition condition = lock.newCondition();//对象监视器

    public  void increment() throws InterruptedException {
        lock.lock();
        try {
            while (datas!=10){
                condition.await();//等待
            }
            datas++;
            System.out.println(Thread.currentThread().getName()+"=>"+datas);
            condition.signalAll();//通知线程++完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            while(datas==10){
                condition.await(); //等待
            }
            datas--;
            System.out.println(Thread.currentThread().getName()+"=>"+datas);
            condition.signalAll(); //通知线程--完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }



}




三:使用Lock锁配置多监视器

上面使用lock锁的模式虽然也能在两条线程的情况下保证一个操作的有序性,但一旦线程数达到三条或者更高就会出错,因此需要制定多个监视器来对不同的线程进行一个更加精确的有序唤醒。

//使用多个监视器进行有序唤醒
public class NewProductCustomer2 {
    public static void main(String[] args) {
        Customer2 c = new Customer2();
        new Thread(()->{for(int i=1;i<=10;i++)c.A();},"Thread01 ").start();
        new Thread(()->{for(int i=1;i<=10;i++)c.B();},"Thread02 ").start();
        new Thread(()->{for(int i=1;i<=10;i++)c.C();},"Thread03 ").start();

    }
}

class Customer2{
    private int data3 = 1;
    private Lock lock = new ReentrantLock();//获取lock锁
    Condition condition1 = lock.newCondition();//监视器
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

    public void A(){
        lock.lock();
        try {
            //while防止虚假唤醒
            while(data3!=1){
                condition1.await();//线程等待
            }
            data3 = 2;
            System.out.println(Thread.currentThread().getName()+"set "+data3+"number data");
            condition2.signal();//线程通知
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void B() {
        lock.lock();
        try {
            //while防止虚假唤醒
            while(data3!=2){
                condition2.await(); //线程等待
            }
            data3 = 3;
            System.out.println(Thread.currentThread().getName()+"get "+data3+"number data");
            condition3.signal();//线程唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void C() {
        lock.lock();
        try {
            //while防止虚假唤醒
            while(data3!=3){
                condition3.await(); //线程等待
            }
            data3 = 1;
            System.out.println(Thread.currentThread().getName()+"get "+data3+"number data");
            condition1.signal();//线程唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deeeelete

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值