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

2020-11-17  本文已影响0人  i小雨

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
上一篇下一篇

猜你喜欢

热点阅读