2. Lock锁,生产者消费者问题

 

 

 

 

 公平锁:十分公平,先来后到

非公平锁:可以插队(默认)

Synchronized

public class SaleTicketDemo01 {
    //并发,多线程操作同一个资源类,把资源类丢入线程就行
    //lambda表达式 (参数)->{代码}
    public static void main(String[] args) {
        final Ticket ticket = new Ticket();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "A").start();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "B").start();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "C").start();
    }
}

//资源类 属性+方法
class Ticket {
    private int number = 50;

    //卖票 (传统方式解决并发问题synchronized)本质是排队+锁
    public synchronized void sale() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
        }
    }
}

lock锁

//在真正的多线程开发中,线程就是一个资源类没有任何附属关系
public class SaleTicketDemo02 {
    //并发,多线程操作同一个资源类,把资源类丢入线程就行
    //lambda表达式 (参数)->{代码}
    public static void main(String[] args) {
        final Ticket ticket = new Ticket();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "A").start();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "B").start();
        new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "C").start();
    }
}
//资源类 属性+方法
class Ticket2 {
    private int number = 50;
    Lock lock=new ReentrantLock();//可重入锁 通过true、false来改变成公平、非公平

    //卖票
    public void sale() {
        lock.lock();//上锁
        try{
            //业务代码
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();//解锁
        }
    }
}

 

 生产者消费者问题:两个线程实现0 1 0 1数字改变

public class A {
    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();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
    }
}

//资源类
class Data{
    private int num=0;
    //+1
    public synchronized void increment() throws InterruptedException {
        if(num!=0){
            this.wait();
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();//通知其他线程我已经完毕了
    }

    //+1
    public synchronized void decrement() throws InterruptedException {
        if(num==0){
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();//通知其他线程我已经完毕了
    }
}

问题存在,如果是四个线程还安全吗(不安全)

 

 if 改为wihle判断就可以解决四条线程的该问题

就是用if判断的话,唤醒后线程会从wait之后的代码开始运行,但是不会重新判断if条件,直接继续运行if代码块之后的代码,而如果使用while的话,也会从wait之后的代码运行,但是唤醒后会重新判断循环条件,如果不成立再执行while代码块之后的代码块,成立的话继续wait。

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

public class B {
    public static void main(String[] args) {
        Data2 data=new Data2();
        new Thread(()->{ for (int i = 0; i < 10; i++) { data.increment(); } },"A").start();
        new Thread(()->{ for (int i = 0; i < 10; i++) { data.decrement(); } },"B").start();
    }
}

//资源类
class Data2{
    private int num=0;
    Lock lock=new ReentrantLock();
    Condition condition = lock.newCondition();//取代了对象监视器的方法

    //+1
    public void increment() {
        lock.lock();
        try{
            while(num!=0){
                condition.await();//等待
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            condition.signalAll();//唤醒全部

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    //+1
    public void decrement() {
        lock.lock();
        try {
            while(num==0){
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

Condition可以精准的通知和唤醒线程

public class C {
    public static void main(String[] args) {
        Data3 data = new Data3();
        new Thread(() -> { for (int i = 0; i < 5; i++) { data.printA(); } }, "A").start();
        new Thread(() -> { for (int i = 0; i < 5; i++) { data.printB(); } }, "B").start();
        new Thread(() -> { for (int i = 0; i < 5; i++) { data.printC(); } }, "C").start();
    }
}

//资源类
class Data3 {
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();//取代了对象监视器的方法
    Condition condition2 = lock.newCondition();//取代了对象监视器的方法
    Condition condition3 = lock.newCondition();//取代了对象监视器的方法
    private int number = 1; //1,2,3->A,B,C

    public void printA() {
        lock.lock();//锁必须上在外面
        try {
            while (number != 1) {
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "AAAA");
            number = 2;
            condition2.signal();//1 执行完了去唤醒2
        } 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() + "BBBB");
            number = 3;
            condition3.signal();//2 执行完了去唤醒3
        } 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() + "CCCC");
            number = 1;
            condition1.signal();//去唤醒1
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

 

posted @ 2021-07-03 22:11  一拳超人的逆袭  阅读(42)  评论(0编辑  收藏  举报