多线程编写模板套路(lock版)

1) 在高内聚低耦合的前提下,线程操作资源类

资源类

class Ticket{
    private int num = 30;

    public void sale(){
        System.out.println("sale");
    }
}

主进程

    public static void main(String[] args) {
        //创建资源类
        Ticket ticket = new Ticket();

        //线程操作资源类
        new Thread(()->{
            ticket.sale();
        },"A").start();
    }

 

2) 判断/干活/通知

资源类

class ShareDate{
    private int numble = 0;
    private Lock lock = new ReentrantLock();
    private Condition[] condition = {
            lock.newCondition(),
            lock.newCondition(),
            lock.newCondition()
    };

    public void printByNum(int num){

        lock.lock();
        try{
            //判断
            if(numble != num) {
                condition[num].await();
            }
            //干活
            for (int i = 0; i < 2 * (num+1); i++){
                System.out.println(Thread.currentThread().getName() + "\t" + (i+1));
            }
            //通知
            numble = ++numble % 3;
            condition[numble].signal();

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}

主进程

    public static void main(String[] args) {
        //线程控制资源类
        ShareDate shareDate = new ShareDate();
        new Thread(()->{
            for(int i = 0; i < 4; i++){
                shareDate.printByNum(0);
            }
        },"A").start();

        new Thread(()->{
            for(int i = 0; i < 4; i++){
                shareDate.printByNum(1);
            }
        },"B").start();

        new Thread(()->{
            for(int i = 0; i < 4; i++){
                shareDate.printByNum(2);
            }
        },"C").start();
    }

  在多线程世界中,如果使用if作为判断语句,则会出现预料之外的结果:

    资源类

class NumberDemo{
    private int num = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    public void incr(){
        lock.lock();
        try{
            //判断
            if(num != 0){
                condition1.await();
            }
            //干活
            num++;
            System.out.println(Thread.currentThread().getName() + "\t:\t" + num);
            //通知
            condition2.signal();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }

    public void desc(){
        lock.lock();
        try{
            if(num != 1){
                condition2.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "\t:\t" + num);
            condition1.signal();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}

  主进程

    public static void main(String[] args) {
        NumberDemo number = new NumberDemo();
        new Thread(()->{
            for (int i = 0; i < 10; i++){
                number.incr();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++){
                number.incr();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++){
                number.desc();
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++){
                number.desc();
            }
        },"D").start();
    }

  结果:

    

 

    出现了意料之外的结果:-1

    解决方法:不使用if来判断语句,而是使用while来代替

3) 使用while防止虚假唤醒

class ShareDate{
    private int numble = 0;
    private Lock lock = new ReentrantLock();
    private Condition[] condition = {
            lock.newCondition(),
            lock.newCondition(),
            lock.newCondition()
    };

    public void printByNum(int num){

        lock.lock();
        try{
            //判断
            while(numble != num) {
                condition[num].await();
            }
            //干活
            for (int i = 0; i < 2 * (num+1); i++){
                System.out.println(Thread.currentThread().getName() + "\t" + (i+1));
            }
            //通知
            numble = ++numble % 3;
            condition[numble].signal();

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}

 

posted @ 2021-02-26 23:57  樱花葬礼  阅读(51)  评论(0)    收藏  举报