发 帖  
原厂入驻New
申请华秋企业认证 多层板首单免费打样!
30s提交资料,10分钟通过审核(免费赔付+顺丰包邮)>>立即报名

[经验] 【java】两种方式实现线程通信:三个线程交替打印AABBCC

2019-9-20 16:38:22  416 java 线程通信
分享
2

多线程之间是抢占资源的,使用线程通信可以达到线程按序执行的目的

线程共享资源类, 首先创建一个资源类, 包含三个打印的方法以及首次打印的字符串
多个线程访问,方法加synchronized同步锁

  1. class Resource {

  2.     String currentPrint = "AA"; // 初始打印,打印之后赋值为下一个要打印的内容

  3.     /**
  4.      * 打印AA
  5.      * [url=home.php?mod=space&uid=3142012]@param[/url] next 下一个要打印的字符串
  6.      * @throws InterruptedException
  7.      */
  8.     public synchronized void printAA(String next) throws InterruptedException {
  9.               // 不是要打印的内容, 阻塞线程
  10.         while (!Objects.equals(currentPrint, "AA")) {
  11.             wait();
  12.         }
  13.         for (int i = 0; i < 3; i++) {
  14.             System.out.println(Thread.currentThread().getName() + ": AA");
  15.         }
  16.         currentPrint= next;
  17.         // 随机唤醒一个线程
  18.         notIFy();
  19.     }

  20.     /**
  21.      * 打印BB
  22.      * @param next 下一个要打印的字符串
  23.      * @throws InterruptedException
  24.      */
  25.     public synchronized void printBB(String next) throws InterruptedException {
  26.               // 不是要打印的内容, 阻塞线程
  27.         while (!Objects.equals(currentPrint, "BB")) {
  28.             wait();
  29.         }
  30.         for (int i = 0; i < 3; i++) {
  31.             System.out.println(Thread.currentThread().getName() + ": BB");
  32.         }
  33.         currentPrint= next;
  34.         // 随机唤醒一个线程
  35.         notify();
  36.     }

  37.     /**
  38.      * 打印CC
  39.      * @throws InterruptedException
  40.      */
  41.     public synchronized void printCC() throws InterruptedException {
  42.             // 不是要打印的内容, 阻塞线程
  43.         while (!Objects.equals(currentPrint, "CC")) {
  44.             wait();
  45.         }
  46.         for (int i = 0; i < 3; i++) {
  47.             System.out.println(Thread.currentThread().getName() + ": CC");
  48.         }
  49.     }
  50. }
复制代码

创建线程执行程序进行交替打印
  1. public class AABBCC {

  2.     public static void main(String[] args) {
  3.         ThreadPoolExecutor threadPoolExecutor = null;
  4.         try {
  5.             // 创建一个最大长度为3的线程池
  6.             threadPoolExecutor = new ThreadPoolExecutor(3, 3, 0,
  7.                     TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
  8.             Resource resource = new Resource();
  9.             // 将要执行的任务插入到集合中
  10.             List<Runnable> list = new ArrayList<>();
  11.             list.add(()->{try { resource.printAA("BB"); } catch (InterruptedException e) { e.printStackTrace(); }});
  12.             list.add(()->{try { resource.printBB("CC"); } catch (InterruptedException e) { e.printStackTrace(); }});
  13.             list.add(()->{try { resource.printCC();} catch (InterruptedException e) {e.printStackTrace();}});
  14.             for (int i = 0; i < list.size(); i++) {
  15.                 threadPoolExecutor.execute(list.get(i));
  16.             }
  17.         } catch (Exception e) {
  18.             e.printStackTrace();
  19.         } finally {
  20.             // 关闭线程池
  21.             if (threadPoolExecutor != null) {
  22.                 threadPoolExecutor.shutdown();
  23.             }
  24.         }
  25.     }
  26. }
复制代码


执行结果
aaa.png
资源类冗余代码进行优化
  1.     /**
  2.      * 打印字符串
  3.      * @param currentPrintParam 当前
  4.      * @param next 下一个
  5.      * @param times 打印次数
  6.      * @throws InterruptedException
  7.      */
  8.     public synchronized void printStr(String currentPrintParam,String next, int times) throws InterruptedException {
  9.               // 不是要打印的内容, 阻塞线程
  10.         while (!Objects.equals(currentPrint, currentPrintParam)) {
  11.             wait();
  12.         }
  13.         for (int i = 0; i < times; i++) {
  14.             System.out.println(Thread.currentThread().getName() + ": "+ currentPrint);
  15.         }
  16.         currentPrint = next;
  17.         // 随机唤醒一个线程
  18.         notify();
  19.     }
复制代码


调用方法替换
  1.             Resource resource = new Resource();
  2.             // 将要执行的任务插入到集合中
  3.             List<Runnable> list = new ArrayList<>();
  4.             list.add(()->{try { resource.printStr("AA", "BB", 3); } catch (InterruptedException e) { e.printStackTrace(); }});
  5.             list.add(()->{try { resource.printStr("BB", "CC", 3); } catch (InterruptedException e) { e.printStackTrace(); }});
  6.             list.add(()->{try { resource.printStr("CC", "", 3);} catch (InterruptedException e) {e.printStackTrace();}});
  7.             for (int i = 0; i < list.size(); i++) {
  8.                 threadPoolExecutor.execute(list.get(i));
  9.             }
复制代码
执行结果
bbb.png
JDK5在java.util.concurrent包下提供了Lock并发锁
资源类代码新增
  1.     Lock lock = new ReentrantLock(); // 并发锁
  2.     Condition aCondition = lock.newCondition();
  3.     Condition bCondition = lock.newCondition();
  4.     Condition cCondition = lock.newCondition();

  5.     /**
  6.      * 打印字符串
  7.      * @param currentPrintParam 当前线程打印
  8.      * @param nextPrint 下一个线程打印
  9.      * @param currentCondition 当前线程
  10.      * @param nextCondition 下一个线程
  11.      * @param times 打印次数
  12.      * @throws InterruptedException
  13.      */
  14.     public void lockPrintStr(String currentPrintParam, String nextPrint, Condition currentCondition, Condition nextCondition, int times) {
  15.         lock.lock();
  16.         try {
  17.             // 不是要打印的内容 阻塞线程
  18.             while (!Objects.equals(currentPrint, currentPrintParam)) {
  19.                 currentCondition.await();
  20.             }
  21.             for (int i = 0; i < times; i++) {
  22.                 System.out.println(Thread.currentThread().getName() + ": "+ currentPrint);
  23.             }
  24.             currentPrint = nextPrint;
  25.             // 唤醒下一个线程
  26.             if (!Objects.isNull(nextCondition)) {
  27.                 nextCondition.signal();
  28.             }
  29.         } catch (Exception e) {
  30.             e.printStackTrace();
  31.         } finally {
  32.             // 释放锁
  33.             if (lock != null) {
  34.                 lock.unlock();
  35.             }
  36.         }
  37.     }
复制代码

调用新增的方法
  1.             Resource resource = new Resource();
  2.             // 将要执行的任务插入到集合中
  3.             List<Runnable> list = new ArrayList<>();
  4.             list.add(()->{resource.lockPrintStr("AA", "BB", resource.aCondition, resource.bCondition, 3);});
  5.             list.add(()->{resource.lockPrintStr("BB", "CC", resource.bCondition, resource.cCondition, 3);});
  6.             list.add(()->{resource.lockPrintStr("CC", "", resource.cCondition, null, 3);});
  7.             for (int i = 0; i < list.size(); i++) {
  8.                 threadPoolExecutor.execute(list.get(i));
  9.             }
复制代码

ccc.png



多次执行的结果中可以看出,由三个线程交替打印AABBCC

总结:
线程通信其中两种方式 Object类下wait()、notify()/notifyAll(),以及JDK5以后提供的Lock下Condition内部类的await()、signal()方法。
使用wait/notify进行线程通信只能够随机唤醒,增加了上下文的切换时间,使用await/signal可以实现精准唤醒,java集合框架中的队列就采用了后者实现线程通信

评论

高级模式
您需要登录后才可以回帖 登录 | 注册

发经验
关闭

站长推荐 上一条 /10 下一条

快速回复 返回顶部 返回列表