gpt4 book ai didi

Java并发之传统线程同步通信技术代码详解

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 28 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java并发之传统线程同步通信技术代码详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

本文研究的主要是Java并发之传统线程同步通信技术的相关代码示例,具体介绍如下.

先看一个问题:

有两个线程,子线程先执行10次,然后主线程执行5次,然后再切换到子线程执行10,再主线程执行5次……如此往返执行50次.

看完这个问题,很明显要用到线程间的通信了, 先分析一下思路:首先肯定要有两个线程,然后每个线程中肯定有个50次的循环,因为每个线程都要往返执行任务50次,主线程的任务是执行5次,子线程的任务是执行10次。线程间通信技术主要用到wait()方法和notify()方法。wait()方法会导致当前线程等待,并释放所持有的锁,notify()方法表示唤醒在此对象监视器上等待的单个线程。下面来一步步完成这道线程间通信问题.

首先不考虑主线程和子线程之间的通信,先把各个线程所要执行的任务写好:

java" id="highlighter_2962">
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class TraditionalThreadCommunication {
     public static void main(String[] args) {
         //开启一个子线程
         new Thread( new Runnable() {
             @Override
                   public void run() {
                 for ( int i = 1 ; i <= 50 ; i ++) {
                     synchronized (TraditionalThreadCommunication. class ) {
                         //子线程任务:执行10次       
                         for ( int j = 1 ;j <= 10 ; j ++) {
                             System.out.println( "sub thread sequence of " + j + ", loop of " + i);
                         }
                     }
                 }
             }
         }
         ).start();
         //main方法即主线程
         for ( int i = 1 ; i <= 50 ; i ++) {
             synchronized (TraditionalThreadCommunication. class ) {
                 //主线程任务:执行5次
                 for ( int j = 1 ;j <= 5 ; j ++) {
                     System.out.println( "main thread sequence of " + j + ", loop of " + i);
                 }
             }
         }
     }
}

如上,两个线程各有50次大循环,执行50次任务,子线程的任务是执行10次,主线程的任务是执行5次。为了保证两个线程间的同步问题,所以用了synchronized同步代码块,并使用了相同的锁:类的字节码对象。这样可以保证线程安全。但是这种设计不太好,就像我在上一节的死锁中写的一样,我们可以把线程任务放到一个类中,这种设计的模式更加结构化,而且把不同的线程任务放到同一个类中会很容易解决同步问题,因为在一个类中很容易使用同一把锁。所以把上面的程序修改一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TraditionalThreadCommunication {
     public static void main(String[] args) {
         Business bussiness = new Business();
         //new一个线程任务处理类
         //开启一个子线程
         new Thread( new Runnable() {
             @Override
                   public void run() {
                 for ( int i = 1 ; i <= 50 ; i ++) {
                     bussiness.sub(i);
                 }
             }
         }
         ).start();
         //main方法即主线程
         for ( int i = 1 ; i <= 50 ; i ++) {
             bussiness.main(i);
         }
     }
}
//要用到的共同数据(包括同步锁)或共同的若干个方法应该归在同一个类身上,这种设计正好体现了高类聚和程序的健壮性。
class Business {
     public synchronized void sub( int i) {
         for ( int j = 1 ;j <= 10 ; j ++) {
             System.out.println( "sub thread sequence of " + j + ", loop of " + i);
         }
     }
     public synchronized void main( int i) {
         for ( int j = 1 ;j <= 5 ; j ++) {
             System.out.println( "main thread sequence of " + j + ", loop of " + i);
         }
     }

经过这样修改后,程序结构更加清晰了,也更加健壮了,只要在两个线程任务方法上加上synchronized关键字即可,用的都是this这把锁。但是现在两个线程之间还没有通信,执行的结果是主线程循环执行任务50次,然后子线程再循环执行任务50次,原因很简单,因为有synchronized同步.

下面继续完善程序,让两个线程之间完成题目中所描述的那样通信:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class TraditionalThreadCommunication {
     public static void main(String[] args) {
         Business bussiness = new Business();
         //new一个线程任务处理类
         //开启一个子线程
         new Thread( new Runnable() {
             @Override
                   public void run() {
                 for ( int i = 1 ; i <= 50 ; i ++) {
                     bussiness.sub(i);
                 }
             }
         }
         ).start();
         //main方法即主线程
         for ( int i = 1 ; i <= 50 ; i ++) {
             bussiness.main(i);
         }
     }
}
//要用到共同数据(包括同步锁)或共同的若干个方法应该归在同一个类身上,这种设计正好体现了高雷剧和程序的健壮性。
class Business {
     private Boolean bShouldSub = true ;
     public synchronized void sub( int i) {
         while (!bShouldSub) {
             //如果不轮到自己执行,就睡
             try {
                 this .wait();
                 //调用wait()方法的对象必须和synchronized锁对象一致,这里synchronized在方法上,所以用this
             }
             catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
         for ( int j = 1 ;j <= 10 ; j ++) {
             System.out.println( "sub thread sequence of " + j + ", loop of " + i);
         }
         bShouldSub = false ;
         //改变标记
         this .notify();
         //唤醒正在等待的主线程
     }
     public synchronized void main( int i) {
         while (bShouldSub) {
             //如果不轮到自己执行,就睡
             try {
                 this .wait();
             }
             catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
         for ( int j = 1 ;j <= 5 ; j ++) {
             System.out.println( "main thread sequence of " + j + ", loop of " + i);
         }
         bShouldSub = true ;
         //改变标记
         this .notify();
         //唤醒正在等待的子线程
     }
}

首先,先不说具体的程序实现,就从结构上来看,已经体会到了这种设计的好处了:主函数里不用修改任何东西,关于线程间同步和线程间通信的逻辑全都在Business类中,主函数中的不同线程只需要调用放在该类中对应的任务即可。体现了高类聚的好处.

再看一下具体的代码,首先定义一个boolean型变量来标识哪个线程该执行,当不是子线程执行的时候,它就睡,那么很自然主线程就执行了,执行完了,修改了bShouldSub并唤醒了子线程,子线程这时候再判断一下while不满足了,就不睡了,就执行子线程任务,同样地,刚刚主线程修改了bShouldSub后,第二次循环来执行主线程任务的时候,判断while满足就睡了,等待子线程来唤醒。这样逻辑就很清楚了,主线程和子线程你一下我一下轮流执行各自的任务,这种节奏共循环50次.

另外有个小小的说明:这里其实用if来判断也是可以的,但是为什么要用while呢?因为有时候线程会假醒(就好像人的梦游,明明正在睡,结果站起来了),如果用的是if的话,那么它假醒了后,就不会再返回去判断if了,那它就很自然的往下执行任务,好了,另一个线程正在执行呢,啪叽一下就与另一个线程之间相互影响了。但是如果是while的话就不一样了,就算线程假醒了,它还会判断一下while的,但是此时另一个线程在执行啊,bShouldSub并没有被修改,所以还是进到while里了,又被睡了~所以很安全,不会影响另一个线程!官方JDK文档中也是这么干的.

线程间通信就总结到这吧~ 。

总结 。

以上就是本文关于Java并发之传统线程同步通信技术代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。

原文链接:http://blog.csdn.net/eson_15/article/details/51530778 。

最后此篇关于Java并发之传统线程同步通信技术代码详解的文章就讲到这里了,如果你想了解更多关于Java并发之传统线程同步通信技术代码详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com