美文网首页
1、JUC(lock和synchronized比较,生产者消费者

1、JUC(lock和synchronized比较,生产者消费者

作者: i小雨 | 来源:发表于2020-11-17 11:12 被阅读0次

    1、Lock锁

    Synchronized和Lock的区别:参考

    1、synchronized是内置关键字,Lock是一个类(接口)
    2、synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
    3、synchronized会自动释放锁,lock必须要手动释放,(如果不释放,会形成死锁
    4、synchronized中线程1如果获得锁,线程2就会一直等待,直到线程1释放;lock锁就不会,tryLcok();
    5、synchronized可重入锁,不可以中断,非公平锁;Lock锁可重入锁,可以判断锁,默认非公平(可以设置)
    6、适合锁少量的代码同步问题;lock适合锁大量的同步代码(灵活度高)

    锁是什么?如何判断锁的是谁?

    synchronized锁的对象是方法的调用者!(对象)
    如果是静态同步方法,则锁的是Class(类)

    2、生产者和消费者问题

    生产者和消费者问题(线程通信)(使用synchronized、wait()、notifyAll())
    拓展问题:java中的notify和notifyAll有什么区别

    package com.company.ThreadTest;
    
    /**
     * 线程之间的通信问腿:生产者和消费者
     * 线程交替执行 A  B 操作同一个变量  num=0
     * A num+1
     * B num-1
     */
    public class TestProductorAndConsumer {
    
        public static void main(String[] args) {
    
            Data data = new Data();
    
            //A线程
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"A").start();
    
            //B线程
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"B").start();
        }
    }
    
    /**
     * 1、判断等待
     * 2、业务
     * 3、通知
     */
    class Data{ //资源类
    
        private int number = 0;
    
        //+1
        public synchronized void increment() throws InterruptedException {
            //判断等待
            if (number!=0){
                //等待
                this.wait();
            }
            //业务
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知B线程可以消费了,我+1完毕
            this.notifyAll();
    
        }
        //+1
        public synchronized void decrement() throws InterruptedException {
            //判断等待
            if (number==0){
                //等待
                this.wait();
            }
            //业务
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知A线程可以生产了,我-1完毕
            this.notifyAll();
    
        }
    
    }
    

    结果:

    A=>1
    B=>0
    A=>1
    B=>0
    A=>1
    B=>0
    A=>1
    B=>0
    A=>1
    B=>0
    

    问题:上述示例如果存在ABCD四个线程!结果可能出现如下:(虚假唤醒)

    什么是虚假唤醒:当一个条件满足时,很多线程都被唤醒了,但是只有其中部分是有用的唤醒,其它的唤醒都是无用功。比如说买货,如果商品本来没有货物,突然进了一件商品,这是所有的线程都被唤醒了,但是只能一个人买,所以其他人都是假唤醒,获取不到对象的锁

    package com.company.ThreadTest;
    
    /**
     * 线程之间的通信问腿:生产者和消费者
     * 线程交替执行 A  B 操作同一个变量  num=0
     * A num+1
     * B num-1
     */
    public class TestProductorAndConsumer {
    
        public static void main(String[] args) {
    
            Data data = new Data();
    
            //A线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"A").start();
    
            //B线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"B").start();
    
            //C线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"C").start();
    
            //D线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"D").start();
        }
    }
    
    /**
     * 1、判断等待
     * 2、业务
     * 3、通知
     */
    class Data{ //资源类
    
        private int number = 0;
    
        //+1
        public synchronized void increment() throws InterruptedException {
            //判断等待
            if (number!=0){
                //等待
                this.wait();
            }
            //业务
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知B线程可以消费了,我+1完毕
            this.notifyAll();
    
        }
        //+1
        public synchronized void decrement() throws InterruptedException {
            //判断等待
            if (number==0){
                //等待
                this.wait();
            }
            //业务
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            //通知A线程可以生产了,我-1完毕
            this.notifyAll();
    
        }
    
    }
    
    A=>1
    B=>0
    C=>1
    A=>2
    C=>3
    B=>2
    B=>1
    B=>0
    C=>1
    A=>2
    C=>3
    B=>2
    C=>3
    D=>2
    D=>1
    D=>0
    A=>1
    D=>0
    A=>1
    D=>0
    

    虚假唤醒的解决办法:

    只需将if (number!=0){} 换成while(number!=0){}

    因为if只会执行一次,执行完会接着向下执行if()外边的;而while不会,直到条件满足才会向下执行while()外边的

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

    JUC版的用法:

    1605515573(1).png
    1605515700(1).jpg
    package com.company.ThreadTest;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 线程之间的通信问腿:生产者和消费者
     * 线程交替执行 A  B 操作同一个变量  num=0
     * A num+1
     * B num-1
     */
    public class TestJUCProductorAndConsumer {
    
        public static void main(String[] args) {
    
            Data2 data = new Data2();
    
            //A线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"A").start();
    
            //B线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"B").start();
    
            //C线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"C").start();
    
            //D线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"D").start();
        }
    }
    
    /**
     * 1、判断等待
     * 2、业务
     * 3、通知
     */
    class Data2{ //资源类
    
        private int number = 0;
    
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
    
        //condition.await();//等待
        //condition.signalAll();//唤醒全部
    
        //+1
        public void increment() throws InterruptedException {
            lock.lock();//上锁
            try {
                //业务代码
                //判断等待
                while (number!=0){
                    //等待
                    condition.await();
                }
                //业务
                number++;
                System.out.println(Thread.currentThread().getName()+"=>"+number);
                //通知B线程可以消费了,我+1完毕
                condition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock(); //释放锁
            }
    
    
        }
        //+1
        public void decrement() throws InterruptedException {
            lock.lock();//上锁
            try {
                //判断等待
                while (number==0){
                    //等待
                    condition.await();
                }
                //业务
                number--;
                System.out.println(Thread.currentThread().getName()+"=>"+number);
                //通知A线程可以生产了,我-1完毕
                condition.signalAll();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();//释放锁
            }
    
    
        }
    
    }
    

    结果:

    A=>1
    B=>0
    C=>1
    B=>0
    C=>1
    B=>0
    C=>1
    B=>0
    C=>1
    B=>0
    C=>1
    D=>0
    A=>1
    D=>0
    A=>1
    D=>0
    A=>1
    D=>0
    A=>1
    D=>0
    

    思考:上述结果为随机状态,如何让ABCD变得有序

    Condition(按ABC的顺序打印)

    package com.company.ThreadTest;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 线程之间的通信问腿:生产者和消费者
     * 线程交替执行 A  B 操作同一个变量  num=0
     * A num+1
     * B num-1
     */
    public class TestJUCProductorAndConsumer2 {
    
        public static void main(String[] args) {
    
            Data3 data = new Data3();
    
            //A线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    data.printA();
                }
            },"A").start();
    
            //B线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    data.printB();
                }
            },"B").start();
    
            //C线程
            new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    data.printC();
                }
            },"C").start();
    
        }
    }
    
    /**
     * 1、判断等待
     * 2、业务
     * 3、通知
     */
    class Data3{ //资源类
    
        private int number = 1;
    
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
    
    
        public void printA(){
            lock.lock();
            try {
                while (number!=1){
                    condition1.await();
                }
                System.out.println(Thread.currentThread().getName()+"-->AAAAA");
                number = 2;
                //唤醒指定的人B
                condition2.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printB(){
            lock.lock();
            try {
                while (number!=2){
                    condition2.await();
                }
                System.out.println(Thread.currentThread().getName()+"-->BBBBB");
                number = 3;
                //唤醒指定的人C
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printC(){
            lock.lock();
            try {
                while (number!=3){
                    condition3.await();
                }
                System.out.println(Thread.currentThread().getName()+"-->CCCCC");
                number = 1;
                //唤醒指定的人
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
    }
    

    结果:

    A-->AAAAA
    B-->BBBBB
    C-->CCCCC
    A-->AAAAA
    B-->BBBBB
    C-->CCCCC
    A-->AAAAA
    B-->BBBBB
    C-->CCCCC
    A-->AAAAA
    B-->BBBBB
    C-->CCCCC
    A-->AAAAA
    B-->BBBBB
    C-->CCCCC
    

    相关文章

      网友评论

          本文标题:1、JUC(lock和synchronized比较,生产者消费者

          本文链接:https://www.haomeiwen.com/subject/dyzvbktx.html