java线程互斥与同步_Java中的线程--线程的互斥与同步通信

Java中的线程之前也提到过,但是还是想再详细的学习一下,跟着张孝祥老师,系统的再学习一下。

一、线程中的互斥

线程安全中的问题解释:线程安全问题可以用银行中的转账

例题描述:

线程A与线程B分别访问同一个对象的方法,这样就会存在线程安全的问题,方法的作用是打印出字符串中的每一个字符,方法如下:

1 public voidoutput(String name) {2 int len =name.length();3 for (int i = 0; i < len; i++) {4 System.out.print(name.charAt(i));5 }6 System.out.println();7 }

线程A和线程B代码如下:(直接写在了init()方法中了)

1 private voidinit() {2 outputer outputer = newoutputer();3 new Thread(newRunnable() {4 @Override5 public voidrun() {6 while (true) {7 try{8 Thread.sleep(10);9 } catch(InterruptedException e) {10 e.printStackTrace();11 }12 outputer.output("songshengchao");13 }14 }15 }).start();16

17 new Thread(newRunnable() {18 @Override19 public voidrun() {20 while (true) {21 try{22 Thread.sleep(10);23 } catch(InterruptedException e) {24 e.printStackTrace();25 }26 outputer.output("songxiaochao");27 }28 }29 }).start();30 }

测试一下,肯定会出现线程不安全的问题,这是母庸质疑的事实,测试代码如下:

1 public static voidmain(String[] args) {2 newTraditionalThreadSynchronized().init();3 }

三种解决办法,代码如下:

1 public classoutputer {2 public voidoutput(String name) {3 int len =name.length();4 synchronized (this) { //传进来当前调用方法的对象,要求线程用的是同一个对象5 //synchronized (outputer.class) {//这样和outputer3方法达到线程互斥

6 for (int i = 0; i < len; i++) {7 System.out.print(name.charAt(i));8 }9 System.out.println();10 }11 }12

13 //方法上的锁对象用的就是this当前对象

14 public synchronized voidoutput2(String name) {15 int len =name.length();16 for (int i = 0; i < len; i++) {17 System.out.print(name.charAt(i));18 }19 System.out.println();20 }21

22 //output3 想和output方法达到线程互斥

23 public static synchronized voidoutput3(String name) {24 int len =name.length();25 for (int i = 0; i < len; i++) {26 System.out.print(name.charAt(i));27 }28 System.out.println();29 }30 }

注意:至于第三种静态的synchronized方法,在和第一个方法共用时,第一种方法一定是用当前对象的class字节码文件,才能确保两个方法用的同一个对象。

二、线程互斥与通信的经典面试题

面试题:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着在主线程循环100次,如此循环50次,程序如何写???

经验之谈,设计思想,设计思路:

要用到共同数据(包括同步锁)的若干个方法应该归在同一个类上,这种设计正好提现了程序的高内聚与健壮性

思路:先写主线程与子线程的循环,然后在考虑轮流执行。先考虑循环,代码如下:

1 public classTraditionalThreadCommunication {2

3 public static voidmain(String[] args) {4

5 new Thread(newRunnable() {6

7 @Override8 public voidrun() {9 for (int i = 1; i <= 50; i++) {10 synchronized (TraditionalThreadCommunication.class) {11 for (int j = 1; j <= 10; j++) {12 System.out.println("sub thread sequece of" + j + ", loop of " +i);13 }14 }15

16 }17 }18 }).start();19

20 //本身main方法就是主线程,直接可以写循环代码

21 for (int i = 1; i <= 50; i++) {22 synchronized (TraditionalThreadCommunication.class) {23 for (int j = 1; j <= 100; j++) {24 System.out.println("main thread sequece of" + j + ", loop of " +i);25 }26 }27 }28

29 }30 }

代码优化,用面向对象的思想,将那些代码放到一个公共的类中,然后执行类中的不同方法,优化成一个公共的类,代码如下:

1 public classBusiness {2

3 public synchronized void sub(inti){4 for (int j = 1; j <= 10; j++) {5 System.out.println("sub thread sequece of" + j + ", loop of " +i);6 }7 }8

9 public synchronized void main(inti){10 for (int j = 1; j <= 100; j++) {11 System.out.println("main thread sequece of" + j + ", loop of " +i);12 }13 }14 }15

16 ----------------------------------------------------------------------------------------------

17

18 public classTraditionalThreadCommunication {19

20

21 public static voidmain(String[] args) {22 Business business = newBusiness();23 new Thread(newRunnable() {24

25 @Override26 public voidrun() {27 for (int i = 1; i <= 50; i++) {28 business.sub(i);29 }30 }31 }).start();32

33 //本身main方法就是主线程,直接可以写循环代码

34 for (int i = 1; i <= 50; i++) {35 business.main(i);36 }37

38 }39

40 }

最终的完整代码如下(详细注释):

1 public classBusiness {2

3 //是否是子线程执行 默认子线程先执行

4 private boolean bShouldSub = true;5

6 public synchronized void sub(inti) {7 //不是子线程应该执行 让给主线程 子线程执行等待的方法

8 while (!bShouldSub) {9 try{10 this.wait();11 } catch(InterruptedException e) {12 e.printStackTrace();13 }14 }15 for (int j = 1; j <= 10; j++) {16 System.out.println("sub thread sequece of" + j + ", loop of " +i);17 }18 //子线程执行完毕后 让给主线程执行

19 bShouldSub = false;20 //唤醒主线程

21 this.notify();22 }23

24 public synchronized void main(inti) {25 //是子线程应该执行 让给子线程执行 主线程执行等待的方法

26 while(bShouldSub) {27 try{28 this.wait();29 } catch(InterruptedException e) {30 e.printStackTrace();31 }32 }33 for (int j = 1; j <= 100; j++) {34 System.out.println("main thread sequece of" + j + ", loop of " +i);35 }36 //主线程执行费完毕后 交给子线程执行

37 bShouldSub = true;38 //唤醒子线程

39 this.notify();40 }41 }42 ------------------------------------------------------------------------------------------------

43

44 public classTraditionalThreadCommunication {45

46 public static voidmain(String[] args) {47 Business business = newBusiness();48 new Thread(newRunnable() {49

50 @Override51 public voidrun() {52 for (int i = 1; i <= 50; i++) {53 business.sub(i);54 }55 }56 }).start();57

58 //本身main方法就是主线程,直接可以写循环代码

59 for (int i = 1; i <= 50; i++) {60 business.main(i);61 }62

63 }64

65 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值