• [Java多线程]ABC三个线程顺序输出的问题


    大概的问题是这样的:

    有A,B,C三个线程, A线程输出A, B线程输出B, C线程输出C

    要求, 同时启动三个线程, 按顺序输出ABC, 循环10次

    这是一个多线程协同的问题, 本身多线程是没有执行顺序的, 顺序不一定, Java在concurrent里面提供了多线程同步的支持

    使用ReentrantLock来解决, 还有个state整数用来判断轮到谁执行了

     1 import java.util.concurrent.locks.Lock;
     2 import java.util.concurrent.locks.ReentrantLock;
     3 
     4 public class ABC {
     5     private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥
     6     private static int state = 0;
     7     
     8     static class ThreadA extends Thread {
     9         @Override
    10         public void run() {
    11             for (int i = 0; i < 10;) {
    12                 lock.lock();
    13                 if (state % 3 == 0) {
    14                     System.out.print("A");
    15                     state++;
    16                     i++;
    17                 }
    18                 lock.unlock();
    19             }
    20         }
    21     }
    22     
    23     static class ThreadB extends Thread {
    24         @Override
    25         public void run() {
    26             for (int i = 0; i < 10;) {
    27                 lock.lock();
    28                 if (state % 3 == 1) {
    29                     System.out.print("B");
    30                     state++;
    31                     i++;
    32                 }
    33                 lock.unlock();
    34             }
    35         }
    36     }
    37     
    38     static class ThreadC extends Thread {
    39         @Override
    40         public void run() {
    41             for (int i = 0; i < 10;) {
    42                 lock.lock();
    43                 if (state % 3 == 2) {
    44                     System.out.print("C");
    45                     state++;
    46                     i++;
    47                 }
    48                 lock.unlock();
    49             }
    50         }
    51     }
    52     
    53     public static void main(String[] args) {
    54         new ThreadA().start();
    55         new ThreadB().start();
    56         new ThreadC().start();
    57     }
    58     
    59 }

    使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 思路简单

    还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似

     1 import java.util.concurrent.locks.Condition;
     2 import java.util.concurrent.locks.Lock;
     3 import java.util.concurrent.locks.ReentrantLock;
     4 
     5 public class ABC2 {
     6     private static Lock lock = new ReentrantLock();
     7     private static int count = 0;
     8     private static Condition A = lock.newCondition();
     9     private static Condition B = lock.newCondition();
    10     private static Condition C = lock.newCondition();
    11     
    12     static class ThreadA extends Thread {
    13 
    14         @Override
    15         public void run() {
    16             lock.lock();
    17             try {
    18                 for (int i = 0; i < 10; i++) {
    19                     while (count % 3 != 0)
    20                         A.await(); // 会释放lock锁
    21                     System.out.print("A");
    22                     count++;
    23                     B.signal(); // 唤醒相应线程
    24                 }
    25             } catch (InterruptedException e) {
    26                 e.printStackTrace();
    27             } finally {
    28                 lock.unlock();
    29             }
    30         }
    31         
    32     }
    33     
    34     static class ThreadB extends Thread {
    35 
    36         @Override
    37         public void run() {
    38             lock.lock();
    39             try {
    40                 for (int i = 0; i < 10; i++) {
    41                     while (count % 3 != 1)
    42                         B.await();
    43                     System.out.print("B");
    44                     count++;
    45                     C.signal();
    46                 }
    47             } catch (InterruptedException e) {
    48                 e.printStackTrace();
    49             } finally {
    50                 lock.unlock();
    51             }
    52         }
    53         
    54     }
    55     
    56     static class ThreadC extends Thread {
    57 
    58         @Override
    59         public void run() {
    60             lock.lock();
    61             try {
    62                 for (int i = 0; i < 10; i++) {
    63                     while (count % 3 != 2)
    64                         C.await();
    65                     System.out.println("C");
    66                     count++;
    67                     A.signal();
    68                 }
    69             } catch (InterruptedException e) {
    70                 e.printStackTrace();
    71             } finally {
    72                 lock.unlock();
    73             }
    74         }
    75         
    76     }
    77     
    78     public static void main(String[] args) throws InterruptedException {
    79         new ThreadA().start();
    80         new ThreadB().start();
    81         ThreadC threadC = new ThreadC();
    82         threadC.start();
    83         threadC.join();
    84         System.out.println(count);
    85     }
    86 }

    使用信号量也可以, 这个思路最简单, 整个代码也比较简洁

     1 import java.util.concurrent.Semaphore;
     2 
     3 public class ABC3 {
     4     private static Semaphore A = new Semaphore(1);
     5     private static Semaphore B = new Semaphore(1);
     6     private static Semaphore C = new Semaphore(1);
     7     
     8     static class ThreadA extends Thread {
     9 
    10         @Override
    11         public void run() {
    12             try {
    13                 for (int i = 0; i < 10; i++) {
    14                     A.acquire();
    15                     System.out.print("A");
    16                     B.release();
    17                 }
    18             } catch (InterruptedException e) {
    19                 e.printStackTrace();
    20             }
    21         }
    22         
    23     }
    24     
    25     static class ThreadB extends Thread {
    26 
    27         @Override
    28         public void run() {
    29             try {
    30                 for (int i = 0; i < 10; i++) {
    31                     B.acquire();
    32                     System.out.print("B");
    33                     C.release();
    34                 }
    35             } catch (InterruptedException e) {
    36                 e.printStackTrace();
    37             }
    38         }
    39         
    40     }
    41     
    42     static class ThreadC extends Thread {
    43 
    44         @Override
    45         public void run() {
    46             try {
    47                 for (int i = 0; i < 10; i++) {
    48                     C.acquire();
    49                     System.out.println("C");
    50                     A.release();
    51                 }
    52             } catch (InterruptedException e) {
    53                 e.printStackTrace();
    54             }
    55         }
    56         
    57     }
    58     
    59     public static void main(String[] args) throws InterruptedException {
    60         B.acquire(); C.acquire(); // 开始只有A可以获取, BC都不可以获取, 保证了A最先执行
    61         new ThreadA().start();
    62         new ThreadB().start();
    63         new ThreadC().start();
    64     }
    65 }

    注意:

    lock是需要lock所有者去释放的, 即谁lock, 谁释放, 不可以跨线程, 会报java.lang.IllegalMonitorStateException;

    semaphore是没有所有者的说法, 可以跨线程释放和获取.

    这是一道java笔试题, 多线程的问题现在越来越多的出现在笔试中, 要好好学习.

    水平有限, 如有错漏, 请指针, 欢迎拍砖, 共同探讨!

    参考文献:

    1. 深入浅出Java Concurrency: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html
  • 相关阅读:
    xtjh
    Tomcat的安装与使用
    Nginx入门
    git上传本地项目到码云(新手必看)
    GitHub开源项目的发布(使用Docker构建)
    Docker学习笔记(基础篇)
    Mybatis逆向工程
    ElasticSearch学习笔记
    you-get:下载音乐等网页视频技巧
    二叉排序树的添加与删除
  • 原文地址:https://www.cnblogs.com/icejoywoo/p/2724674.html
Copyright © 2020-2023  润新知