JAVA并发如何让线程顺序执行

2020-05-09  本文已影响0人  叶子丶恬

方法一

利用Lock锁中的Condition等待/唤醒机制,让三个线程顺序打印1 ~ N个数值。

public class ThreadQueueDemo {
    static int count = 1;
    static Lock lock = new ReentrantLock();
    
    /**
     * 定义每个线程对应的condition
     */
    static Condition one = lock.newCondition();
    static Condition two = lock.newCondition();
    static Condition three = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new ThreadDemo(one,two),"thread-1");
        Thread thread2 = new Thread(new ThreadDemo(two,three),"thread-2");
        Thread thread3 = new Thread(new ThreadDemo(three,one),"thread-3");
        thread1.start();
        // 稍微等待下,以免线程乱序执行
        Thread.sleep(100);
        thread2.start();
        Thread.sleep(100);
        thread3.start();
    }

   private static class ThreadDemo implements Runnable{
        // 当前线程锁通知条件
        private Condition condition;
        // 保存的下一个线程锁通知条件
        private Condition nextCondition;

        ThreadDemo(Condition condition,Condition nextCondition){
            this.condition = condition;
            this.nextCondition = nextCondition;
        }

        @Override
        public void run() {
            while (true){
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName()+":"+count++);
                    try {
                        // 唤醒下一个线程
                        nextCondition.signal();
                        // 睡眠一下防止执行太快
                        Thread.sleep(500);
                        // 休眠当前线程
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }finally {
                    lock.unlock();
                }
            }
        }
    }
}

大致流程

流程图

方法二

利用队列(Queue)volatileLockSupport::park,LockSupport:unpark实现。

public class QueueTest{

    public static volatile int count = 1;
    public static final int MAX_COUNT = 100;
    public static final int MAX_THREAD_NUM = 3;
    public static volatile boolean flag = true;
    // 无界的队列,使用有界队列时需注意线程数要小于等于队列长度
    public static final Queue queue = new LinkedBlockingQueue();

    public static void main(String[] args){
        // 循环增加线程到阻塞队列
        for (int i = 1; i <= MAX_THREAD_NUM ; i++) {
            queue.add(new Thread(()->{
                while (true){
                    // 将当前线程追加到队列尾部
                    queue.add(Thread.currentThread());
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 让主线程中的循环得以继续
                    flag  = true;
                    // 暂停当前线程
                    LockSupport.park(Thread.currentThread());
                }
            },"Thread-"+i));
        }

       while (count < MAX_COUNT){
           // 利用volatile的可见性来保证线程执行的顺序性
           if (flag) {
               flag = false;
               Thread thread;
               // 取出队列中的线程来执行
               if ((thread = (Thread) queue.poll()) != null) {
                   Thread.State state = thread.getState();
                   //如果为未启动状态,则先启动
                   if (state == Thread.State.NEW) {
                       thread.start();
                   // 如果为等待状态则解除等待
                   } else if (state == Thread.State.WAITING) {
                       LockSupport.unpark(thread);
                   }
               }
           }
       }
       // 中断线程,安全退出
       Thread thread;
       while ((thread = (Thread) queue.poll()) != null) {
           thread.interrupt();
       }

    }
}

大致流程

图片.png

能力有限,如有错误,欢迎指点。。。

上一篇下一篇

猜你喜欢

热点阅读