• 两个线程交替打印A1B2C3D4E5输出,6种实现方式


    第一种,传统方式wait和notify

    1. public static void main(String[] args) {
    2. Object o = new Object();
    3. char[] chars1 = "12345".toCharArray();
    4. char[] chars2 = "ABCDE".toCharArray();
    5. new Thread(()->{
    6. synchronized (o) {
    7. for (int i = 0; i < chars1.length; i++) {
    8. System.out.print(chars1[i]);
    9. o.notify();
    10. try {
    11. o.wait();
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. o.notify();
    17. }
    18. },"t1").start();
    19. new Thread(()->{
    20. synchronized (o) {
    21. for (int i = 0; i < chars2.length; i++) {
    22. System.out.print(chars2[i]);
    23. o.notify();
    24. try {
    25. o.wait();
    26. } catch (InterruptedException e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. o.notify();
    31. }
    32. },"t2").start();
    33. }

    如上代码:思考两个问题wait和notify的顺序可以颠倒吗,为什么for循环后还要notify?

    wait和notify的顺序不能颠倒,因为如果wait在前当前线程就在等待队列中,永远不会被唤醒了

    for循环后还要加notify,是因为两个线程无论哪个最后执行,都会其中有一个在wait,所以要结束等待要加notify,要不程序永不停止

    注意:这种方式保证不了线程t1先于t2执行,可能t2执行后t1在执行,引入门闩解决

    第二种方式:CountDownLatch

    1. public static void main(String[] args) {
    2. Object o = new Object();
    3. CountDownLatch latch = new CountDownLatch(1);
    4. char[] chars1 = "12345".toCharArray();
    5. char[] chars2 = "ABCDE".toCharArray();
    6. new Thread(()->{
    7. latch.countDown();
    8. synchronized (o) {
    9. for (int i = 0; i < chars1.length; i++) {
    10. System.out.print(chars1[i]);
    11. o.notify();
    12. try {
    13. o.wait();
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. o.notify();
    19. }
    20. },"t1").start();
    21. new Thread(()->{
    22. try {
    23. latch.await();
    24. } catch (InterruptedException e) {
    25. e.printStackTrace();
    26. }
    27. synchronized (o) {
    28. for (int i = 0; i < chars2.length; i++) {
    29. System.out.print(chars2[i]);
    30. o.notify();
    31. try {
    32. o.wait();
    33. } catch (InterruptedException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. o.notify();
    38. }
    39. },"t2").start();
    40. }

    第三种方式:LockSupport

    1. static Thread t1 = null,t2 = null;
    2. public static void main(String[] args) {
    3. char[] chars1 = "123456".toCharArray();
    4. char[] chars2 = "ABCDEF".toCharArray();
    5. t1 = new Thread(()->{
    6. for (char a:chars1) {
    7. System.out.print(a);
    8. LockSupport.unpark(t2);//唤醒t2
    9. LockSupport.park();//阻塞本线程
    10. }
    11. });
    12. t2 = new Thread(()->{
    13. for(char b:chars2){
    14. LockSupport.park();
    15. System.out.print(b);
    16. LockSupport.unpark(t1);
    17. }
    18. });
    19. t1.start();
    20. t2.start();
    21. }

    第四种方式:ReentrantLock

    1. public static void main(String[] args) {
    2. ReentrantLock lock = new ReentrantLock();
    3. Condition condition1 = lock.newCondition();
    4. Condition condition2 = lock.newCondition();
    5. char[] chars1 = "12345".toCharArray();
    6. char[] chars2 = "ABCDE".toCharArray();
    7. new Thread(()->{
    8. try {
    9. lock.lock();
    10. for (int i = 0; i < chars1.length; i++) {
    11. System.out.print(chars1[i]);
    12. condition2.signal();
    13. condition1.await();
    14. }
    15. condition2.signal();
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }finally {
    19. lock.unlock();
    20. }
    21. },"t1").start();
    22. new Thread(()->{
    23. try {
    24. lock.lock();
    25. for (int i = 0; i < chars2.length; i++) {
    26. System.out.print(chars2[i]);
    27. condition1.signal();
    28. condition2.await();
    29. }
    30. condition1.signal();
    31. }catch (InterruptedException e) {
    32. e.printStackTrace();
    33. }finally {
    34. lock.unlock();
    35. }
    36. },"t2").start();
    37. }

    第五种方式:TransferQueue

    1. public static void main(String[] args) {
    2. char[] chars1 = "12345".toCharArray();
    3. char[] chars2 = "ABCDE".toCharArray();
    4. TransferQueue<Character> queue = new LinkedTransferQueue<>();
    5. new Thread(()->{
    6. for (int i = 0; i < chars1.length; i++) {
    7. try {
    8. System.out.print(queue.take());
    9. queue.transfer(chars1[i]);
    10. } catch (InterruptedException e) {
    11. e.printStackTrace();
    12. }
    13. }
    14. },"t1").start();
    15. new Thread(()->{
    16. for (int i = 0; i < chars2.length; i++) {
    17. try {
    18. queue.transfer(chars2[i]);
    19. System.out.print(queue.take());
    20. } catch (InterruptedException e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. },"t2").start();
    25. }

    第六种方式:枚举类

    1. enum ReadToRun{T1,T2};
    2. static volatile ReadToRun r = ReadToRun.T1;
    3. public static void main(String[] args) {
    4. char[] chars1 = "123456".toCharArray();
    5. char[] chars2 = "ABCDEF".toCharArray();
    6. new Thread(()->{
    7. for(char a:chars1){
    8. while(r!=ReadToRun.T1){}//若r不等于T1,自旋空转
    9. System.out.print(a);
    10. r = ReadToRun.T2;
    11. }
    12. },"t1").start();
    13. new Thread(()->{
    14. for(char b:chars2){
    15. while(r!=ReadToRun.T2){}//若r不等于T2,自旋空转
    16. System.out.println(b);
    17. r = ReadToRun.T1;
    18. }
    19. },"t2").start();
    20. }

  • 相关阅读:
    慢速排序算法到底有多慢
    单例模式(内存栅栏)
    设计模式一: Observer(观察者模式)
    更换内存条需要注意什么
    无缝数据转换!使用C++ 实现 Excel文件与CSV之间的相互转换
    SAE-J1939-21 (超8字节)多包数据----CAN传输协议
    前后端分离项目,vue+uni-app+php+mysql订座预约小程序系统设计与实现
    迅为RK3568开发Android12系统烧写 Android 固件
    Django(四、路由层)
    8.9模拟赛总结
  • 原文地址:https://blog.csdn.net/star_xing123/article/details/125422859