zoukankan      html  css  js  c++  java
  • JUC 并发编程--02,生产者和消费者 synchronized的写法 , juc的写法. Condition的用法

    synchronized的写法

    class PCdemo{
        public static void main(String[] args) {
            //多个线程操作同一资源
            Data data = new Data();
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-1").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-2").start();
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-3").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-4").start();
        }
    }
    //这是一个资源类,
    class Data {
        private int num = 0;
        //加1
        public synchronized void increment() throws InterruptedException {
            while(num != 0){
                this.wait();
            }
            num++;
            System.out.println("当前线程名字:" + Thread.currentThread().getName() + "加1 操作, num为" + num);
            this.notifyAll();
        }
        //减1
        public synchronized void decrement() throws InterruptedException {
            while(num == 0){
                this.wait();
            }
            num--;
            System.out.println("当前线程名字:" + Thread.currentThread().getName() + "减1 操作, num为" + num);
            this.notifyAll();
        }
    }
    

    结果:

    这里需要注意一个概念: 虚假唤醒,就是说线程被唤醒了, 但不会被通知 如果把资源类Data中的 increment, decrement方法中的while 换为: if, 那么运行的时候, 二个线程的结果是正常的, 如果二个以上就会出错,结果为

    JUC 版本的 生产者和消费者问题

    public class JucPCdemo {
        public static void main(String[] args) {
            //JUC 版本的 就是来替代 synchronized版本的
            DataJ data = new DataJ();
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-1").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-2").start();
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-3").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-4").start();
        }
    
    }
    
    class DataJ{
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
    
        private int num = 0;
        //加1
        public void increment() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(num != 0){
                    condition.await();//这个替代 this.wait()
                }
                num++;
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "加1 操作, num为" + num);
                condition.signalAll();// 这个来替代  this.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
        //减1
        public void decrement() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(num == 0){
                    condition.await();//这个替代 this.wait();
                }
                num--;
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "减1 操作, num为" + num);
                condition.signalAll();// 这个来替代  this.notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    }
    

    结果同样是正确的

    然而 Condition 更强大的是精确通知和精确唤醒, 之前的运行结果线程之间是随机运行的,如果让线程 1,2,3,4 依次循环有序执行, 就要用到Condition

    public class JucPCdemo01 {
        public static void main(String[] args) {
            //JUC 版本的 就是来替代 synchronized版本的
            //4个线程依次循环有序执行, num 初始值为0, 线程1--A,  线程2--B,  线程3--C, 线程4--D
            DataC data = new DataC();
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.printA();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-1").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.printB();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-2").start();
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.printC();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-3").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.printD();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread-4").start();
        }
    
    }
    
    class DataC{
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();//对应A
        private Condition condition2 = lock.newCondition();//对应B
        private Condition condition3 = lock.newCondition();//对应C
        private Condition condition4 = lock.newCondition();//对应D
    
        private String str = "A";
        public void printA() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(! "A".equals(str)){
                    condition1.await();//只要不是 A 就等待
                }
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
                str = "B";
                condition2.signal();//这里指定唤醒 线程2 对应B
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
        public void printB() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(!"B".equals(str)){
                    condition2.await();//只要不是B 就等待
                }
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
                str = "C";
                condition3.signal();//这里指定唤醒 线程3 对应C
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
        public void printC() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(! "C".equals(str)){
                    condition3.await();//只要不是C 就等待
                }
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
                str = "D";
                condition4.signal();//这里指定唤醒 线程4 对应D
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
        public void printD() throws InterruptedException {
            //先加锁
            lock.lock();
            try {
                while(! "D".equals(str)){
                    condition4.await();//只要不是D 就等待
                }
                System.out.println("当前线程名字:" + Thread.currentThread().getName() + "对应str为" + str);
                str = "A";
                condition1.signal();//这里指定唤醒 线程1 对应A
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
    }
    

    运行结果为;

  • 相关阅读:
    Scala: 包对象
    云服务使用技巧
    leetcode上一些常见的链表问题
    数据挖掘的价值
    leetcode上的一些分治算法
    双指针的应用
    KNN算法
    线性回归
    leetcode上的一些单链表
    leetcode上的一些栈、队列问题
  • 原文地址:https://www.cnblogs.com/lvcai/p/13470950.html
Copyright © 2011-2022 走看看