Java深入学习12:线程按目标顺序执行以及Lock锁和Condiiton接口

一、一个多线程问题,有三类线程,分别是A、B、C,如如实现ABCABCABCABCABC,顺次执行。

方案1。代码如下

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadSequenceOutputTest {

    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();

        for(int i=1; i<5; i++){
            //A类线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    threadDemo.outPutA();
                }
            },"A").start();
            //C类线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    threadDemo.outPutB();
                }
            },"B").start();
            //C类线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    threadDemo.outPutC();
                }
            },"C").start();

        }
    }
}


class ThreadDemo{

    private int num = 1;//当前线程标记,123分别对应ABC

    private Lock lock = new ReentrantLock();

    private Condition condition1 = lock.newCondition();//condition1控制A类线程
    private Condition condition2 = lock.newCondition();//condition2控制B类线程
    private Condition condition3 = lock.newCondition();//condition3控制C类线程

    //输出A
    public void outPutA(){
        lock.lock();
        try {
            //如果没有轮到A类线程,则继续等待
            if(num != 1){
                condition1.await();
            }
            //打印线程名称
            System.out.println(Thread.currentThread().getName());
            //num标志切换成B线程
            num = 2;
            //唤醒B类线程
            condition2.signal();
        } catch (InterruptedException e){
           e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    //输出B
    public void outPutB(){
        lock.lock();
        try {
            if(num != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName());
            num = 3;
            condition3.signal();
        } catch (InterruptedException e){
           e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    //输出C
    public void outPutC(){
        lock.lock();
        try {
            if(num != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName());
            num = 1;
            condition1.signal();
        } catch (InterruptedException e){
           e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

 

二、Condiiton接口

1-Condition

   Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作。

  Condition是个接口,基本的方法就是await()和signal()方法;

  Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition() 

  调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用

    Conditon中的await()对应Object的wait();

    Condition中的signal()对应Object的notify();

    Condition中的signalAll()对应Object的notifyAll()。

2-在Java Condition接口的注释中有一个案例如下

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*这是一个简单的生产者消费者模型,生产者往buffer里put,消费者从buffer里take。
1-同一状态的顺序访问: 有三个状态需要顺序访问:buffer的大小count,生产者用于put的游标putptr,消费者用于take的游标takeptr。
2-基于该状态的条件等待: 当count = 0时,消费者的take需要等待;当count = buffer.size(buffer满了),生产者需要等待。
*/
public class BoundedBuffer {

    public static void main(String[] args) {
        BoundedBuffer boundedBuffer = new BoundedBuffer();
        for(int i=1; i<100; i++){
            //生产者
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boundedBuffer.put((int)(Math.random()*100));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            //消费者
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boundedBuffer.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            }

    }


    final Lock lock = new ReentrantLock();
    final Condition notFull  = lock.newCondition();
    final Condition notEmpty = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;
 
    //生产
    public void put(Object x) throws InterruptedException {
        System.out.println("count " + count);
        //上锁
        lock.lock();
        try {
            //如果count已满,设置“未满”进程等待
            while (count == items.length){
                notFull.await();
            }
            //赋值
            items[putptr] = x;
            System.out.println("put " + x);
            //判断put的游标到了最后一位,则移到首位
            if (++putptr == items.length){
                putptr = 0;
            }
            //计数count+1
            ++count;
            //唤起“非空”继承
            notEmpty.signal();
        } finally {
            //释放锁
            lock.unlock();
        }
    }
 
    //消费
    public Object take() throws InterruptedException {
        //上锁
        lock.lock();
        try {
            //当缓存为空是,设置“非空”线程等待
            while (count == 0){
                notEmpty.await();
            }
            //获取当前take游标的value
            Object x = items[takeptr];
            System.out.println("take " + x);
            //判断take的游标如果到了数组末端,则更新为首位
            if (++takeptr == items.length) {
                takeptr = 0;
            }
            //计数-1
            --count;
            //唤醒“未满”线程
            notFull.signal();
            return x;
        } finally {
            //释放锁
            lock.unlock();
        }
    }
}

 

posted on 2020-03-21 20:20  我不吃番茄  阅读(405)  评论(0编辑  收藏  举报