java多线程实现有序输出ABC

所属分类: 软件编程 / java 阅读数: 30
收藏 0 赞 0 分享

3个线程,线程1输出A,线程2输出B,线程3输出C,让这个3个线程循环有序地输出ABCABC…

看到这个题目,感觉很有意思,问题的本质是在多线程执行环境,控制线程的执行顺序,实现的方式有非常多种,本质上需要解决Java多线程环境下的线程执行的同步和利用锁机制来控制线程的执行顺序。

方式1:利用synchronized

这种方式也就是使用java内置的monitor机制,配合wait和notifyAll,代码如下:

(1)利用volatile做线程间资源的同步访问,同时作为线程调度的标志;
(2)利用notifyAll来唤醒其他等待当前的monitor资源的线程;

public class ThreadOrderWithSync {

  private volatile int flag = 'A';
  private final static Object LOCK = new Object();

  Runnable a = () -> {
    while (true) {
      synchronized (LOCK) {
        if (flag == 'A' ) {
          System.out.println("A");

          flag = 'B';
          // let other thread race to get the monitor
          LOCK.notifyAll();
        } else {
          try {
            LOCK.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  };

  Runnable b = () -> {
    while (true) {
      synchronized (LOCK) {
        if (flag == 'B' ) {
          System.out.println("B");

          flag = 'C';
          // let other thread race to get the monitor
          LOCK.notifyAll();
        } else {
          try {
            LOCK.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  };

  Runnable c = () -> {
    while (true) {
      synchronized (LOCK) {
        if (flag == 'C' ) {
          System.out.println("C");

          flag = 'A';
          // let other thread race to get the monitor
          LOCK.notifyAll();
        } else {
          try {
            LOCK.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  };

  public void runTest() {
    Thread ta = new Thread(a);
    Thread tb = new Thread(b);
    Thread tc = new Thread(c);

    ta.start();
    tb.start();
    tc.start();
  }

  public static void main(String[] args) {
    ThreadOrderWithSync sync = new ThreadOrderWithSync();
    sync.runTest();
  }
}

方式2:利用并发包ReentrantLock和Condition的锁机制

上面方式1的synchronized机制,因为当前的所有线程都争用同一个monitor资源,因此只能通过notifyAll来通知其他线程来加锁,因此每次都会出现race condition,但是,通过ReentrantLock的Condition,我们可以精确控制,下一个该唤醒signal的线程是哪一个(因为我们知道执行的顺序是A->B->C的循环),相比synchronized的机制,Condition机制可以更精细化线程的调度设计,代码示例如下:

/**
 * @author xijin.zeng created on 2018/8/31
 * Thrads runing order: A->B->C
 */
public class ThreadOrderWithCondition {

  private static final ReentrantLock LOCK = new ReentrantLock();
  private static final Condition C_A = LOCK.newCondition();
  private static final Condition C_B = LOCK.newCondition();
  private static final Condition C_C = LOCK.newCondition();

  /**
   * init for A to run first
   */
  private volatile int flag = 'A';

  Runnable a = () -> {
    while (true) {
      LOCK.lock();

      if (flag == 'A') {
        System.out.println("A");
        flag = 'B';
        // signal B to run
        C_B.signal();
      } else {
        try {
          // block and wait signal to invoke
          C_A.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      LOCK.unlock();
    }
  };

  Runnable b = () -> {
    while (true) {
      LOCK.lock();

      if (flag == 'B') {
        System.out.println("B");
        flag = 'C';
        // signal C to run
        C_C.signal();
      } else {
        try {
          // block and wait signal to invoke
          C_B.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      LOCK.unlock();
    }
  };

  Runnable c = () -> {
    while (true) {
      LOCK.lock();

      if (flag == 'C') {
        System.out.println("C");
        flag = 'A';
        // signal A to run
        C_A.signal();
      } else {
        try {
          // block and wait signal to invoke
          C_C.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      LOCK.unlock();
    }
  };

  public void runTest() {
    Thread threadA = new Thread(a);
    Thread threadB = new Thread(b);
    Thread threadC = new Thread(c);

    threadA.start();
    threadB.start();
    threadC.start();
  }

  public static void main(String[] args) {
    ThreadOrderWithCondition o = new ThreadOrderWithCondition();
    o.runTest();
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

Springmvc restful配置遇到的小坑

本文是小编给大家带了的Springmvc restful配置遇到的小小坑,小编给大家带来了问题原因及解决办法,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧
收藏 0 赞 0 分享

Java中的匿名内部类小结

java内部类分为: 成员内部类、静态嵌套类、方法内部类、匿名内部类。这篇文章主要介绍了Java中的匿名内部类的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java的云打印Lodop

这篇文章主要介绍了Java的云打印Lodop 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Java线程池框架核心代码解析

这篇文章主要针对Java线程池框架核心代码进行详细解析,分析Java线程池框架的实现ThreadPoolExecutor,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Java 交换两个变量的数值实现方法

下面小编就为大家带来一篇Java 交换两个变量的数值实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

全面了解JAVA_BaseDAO数据处理类

下面小编就为大家带来一篇全面了解JAVA_BaseDAO数据处理类。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

java、python、JavaScript以及jquery循环语句的区别

本篇文章主要介绍java、python、JavaScript以及jquery的循环语句的区别,这里整理了它们循环语句语法跟示例,以便大家阅读,更好的区分它们的不同
收藏 0 赞 0 分享

基于JDBC封装的BaseDao(实例代码)

下面小编就为大家带来一篇基于JDBC封装的BaseDao(实例代码)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

简单通用JDBC辅助类封装(实例)

下面小编就为大家带来一篇简单通用JDBC辅助类封装(实例)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

浅谈java线程中生产者与消费者的问题

下面小编就为大家带来一篇浅谈java线程中生产者与消费者的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多