黑马程序员_java多线程的同步和死锁
2015-11-10 13:18
691 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
-------!--问题的导入每个线程都会有一个运行的时间片,都会有开始和时间片到期的时候。所以我们要注意了:一个线程的时间片到期的时候,此线程有可能执行到程序的任何一个位置而被暂停,然后就进入时间片的轮换,这样就导致多线程的运行结果不可意料。此时我们就需要对线程进行同步处理。!--分析:比如说对于买票系统如下:
【运行结果】:
5
4
3
2
1
0
-1
这里出现了-1,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【使用线程同步解决问题】
采用同步的话,可以使用同步代码块和同步方法两种来完成。【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
比如对于上面的买票的问题,如下:
【运行结果】:(每一秒输出一个结果)
5
4
3
2
1
【同步方法】
也可以采用同步方法。
语法格式为synchronized方法返回类型方法名(参数列表){
//其他代码
}
现在,我们采用同步方法解决上面的问题。
【运行结果】(每秒输出一个)
5
4
3
2
1
提醒一下,当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
此处列举经典的生产者和消费者问题。
【生产者和消费者问题】
先看一段有问题的代码。
【运行结果】:
Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
大家可以从结果中看到,名字和年龄并没有对于。那么如何解决呢?
1)加入同步
2)加入等待和唤醒
先来看看加入同步会是如何。
【运行结果】:
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
从运行结果来看,错乱的问题解决了,现在是Rollen对应20,ChunGe对于100
,但是还是出现了重复读取的问题,也肯定有重复覆盖的问题。如果想解决这个问题,就需要使用Object类帮忙了、
,我们可以使用其中的等待和唤醒操作。
要完成上面的功能,我们只需要修改Info类饥渴,在其中加上标志位,并且通过判断标志位完成等待和唤醒的操作,代码如下:
后语:多练习------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
-------
-------!--问题的导入每个线程都会有一个运行的时间片,都会有开始和时间片到期的时候。所以我们要注意了:一个线程的时间片到期的时候,此线程有可能执行到程序的任何一个位置而被暂停,然后就进入时间片的轮换,这样就导致多线程的运行结果不可意料。此时我们就需要对线程进行同步处理。!--分析:比如说对于买票系统如下:
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 | /** *@authorRollen-Holt **/ class hello implements Runnable{ public void run(){ for ( int i= 0 ;i< 10 ;++i){ if (count> 0 ){ try { Thread.sleep( 1000 ); } catch (InterruptedExceptione){ e.printStackTrace(); } System.out.println(count--); } } } public static void main(String[]args){ hellohe= new hello(); Threadh1= new Thread(he); Threadh2= new Thread(he); Threadh3= new Thread(he); h1.start(); h2.start(); h3.start(); } private int count= 5 ; } |
5
4
3
2
1
0
-1
这里出现了-1,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【使用线程同步解决问题】
采用同步的话,可以使用同步代码块和同步方法两种来完成。【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
比如对于上面的买票的问题,如下:
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 | /** *@authorRollen-Holt **/ class hello implements Runnable{ public void run(){ for ( int i= 0 ;i< 10 ;++i){ synchronized ( this ){ if (count> 0 ){ try { Thread.sleep( 1000 ); } catch (InterruptedExceptione){ e.printStackTrace(); } System.out.println(count--); } } } } public static void main(String[]args){ hellohe= new hello(); Threadh1= new Thread(he); Threadh2= new Thread(he); Threadh3= new Thread(he); h1.start(); h2.start(); h3.start(); } private int count= 5 ; } |
5
4
3
2
1
【同步方法】
也可以采用同步方法。
语法格式为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 | /** *@authorRollen-Holt **/ class hello implements Runnable{ public void run(){ for ( int i= 0 ;i< 10 ; sale(); } } public synchronized void sale(){ if (count> 0 ){ try { Thread.sleep( 1000 ); } catch (InterruptedExceptione){ e.printStackTrace(); } System.out.println(count--); } } public static void main(String[]args){ hellohe= new hello(); Threadh1= new Thread(he); Threadh2= new Thread(he); Threadh3= new Thread(he); h1.start(); h2.start(); h3.start(); } private int count= 5 ; } |
5
4
3
2
1
提醒一下,当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
此处列举经典的生产者和消费者问题。
【生产者和消费者问题】
先看一段有问题的代码。
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | class Info{ public StringgetName(){ return name; } public void setName(Stringname){ this .name=name; } public int getAge(){ return age; } public void setAge( int age){ this .age=age; } private Stringname= "Rollen" ; private int age= 20 ; } /** *生产者 **/ class Producer implements Runnable{ private Infoinfo= null ; Producer(Infoinfo){ this .info=info; } public void run(){ boolean flag= false ; for ( int i= 0 ;i< 25 ;++i){ if (flag){ this .info.setName( "Rollen" ); try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .info.setAge( 20 ); flag= false ; } else { this .info.setName( "chunGe" ); try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .info.setAge( 100 ); flag= true ; } } } } /** *消费者类 **/ class Consumer implements Runnable{ private Infoinfo= null ; public Consumer(Infoinfo){ this .info=info; } public void run(){ for ( int i= 0 ;i< 25 ;++i){ try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } System.out.println( this .info.getName()+ "<---->" + this .info.getAge()); } } } /** *测试类 **/ class hello{ public static void main(String[]args){ Infoinfo= new Info(); Producerpro= new Producer(info); Consumercon= new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } } |
Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
大家可以从结果中看到,名字和年龄并没有对于。那么如何解决呢?
1)加入同步
2)加入等待和唤醒
先来看看加入同步会是如何。
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | class Info{ public StringgetName(){ return name; } public void setName(Stringname){ this .name=name; } public int getAge(){ return age; } public void setAge( int age){ this .age=age; } public synchronized void set(Stringname, int age){ this .name=name; try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .age=age; } public synchronized void get(){ try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } System.out.println( this .getName()+ "<===>" + this .getAge()); } private Stringname= "Rollen" ; private int age= 20 ; } /** *生产者 **/ class Producer implements Runnable{ private Infoinfo= null ; Producer(Infoinfo){ this .info=info; } public void run(){ boolean flag= false ; for ( int i= 0 ;i< 25 ; if (flag){ this .info.set( "Rollen" , 20 ); flag= false ; } else { this .info.set( "ChunGe" , 100 ); flag= true ; } } } } /** *消费者类 **/ class Consumer implements Runnable{ private Infoinfo= null ; public Consumer(Infoinfo){ this .info=info; } public void run(){ for ( int i= 0 ;i< 25 ; try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .info.get(); } } } /** *测试类 **/ class hello{ public static void main(String[]args){ Infoinfo= new Info(); Producerpro= new Producer(info); Consumercon= new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } } |
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
从运行结果来看,错乱的问题解决了,现在是Rollen对应20,ChunGe对于100
,但是还是出现了重复读取的问题,也肯定有重复覆盖的问题。如果想解决这个问题,就需要使用Object类帮忙了、
,我们可以使用其中的等待和唤醒操作。
要完成上面的功能,我们只需要修改Info类饥渴,在其中加上标志位,并且通过判断标志位完成等待和唤醒的操作,代码如下:
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | class Info{ public StringgetName(){ return name; } public void setName(Stringname){ this .name=name; } public int getAge(){ return age; } public void setAge( int age){ this .age=age; } public synchronized void set(Stringname, int age){ if (!flag){ try { super .wait(); } catch (Exceptione){ e.printStackTrace(); } } this .name=name; try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .age=age; flag= false ; super .notify(); } public synchronized void get(){ if (flag){ try { super .wait(); } catch (Exceptione){ e.printStackTrace(); } } try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } System.out.println( this .getName()+ "<===>" + this .getAge()); flag= true ; super .notify(); } private Stringname= "Rollen" ; private int age= 20 ; private boolean flag= false ; } /** *生产者 **/ class Producer implements Runnable{ private Infoinfo= null ; Producer(Infoinfo){ this .info=info; } public void run(){ boolean flag= false ; for ( int i= 0 ;i< 25 ; if (flag){ this .info.set( "Rollen" , 20 ); flag= false ; } else { this .info.set( "ChunGe" , 100 ); flag= true ; } } } } /** *消费者类 **/ class Consumer implements Runnable{ private Infoinfo= null ; public Consumer(Infoinfo){ this .info=info; } public void run(){ for ( int i= 0 ;i< 25 ; try { Thread.sleep( 100 ); } catch (Exceptione){ e.printStackTrace(); } this .info.get(); } } } /** *测试类 **/ class hello{ public static void main(String[]args){ Infoinfo= new Info(); Producerpro= new Producer(info); Consumercon= new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } } |
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 | 【程序运行结果】: Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 ChunGe<===> 100 Rollen<===> 20 先在看结果就可以知道,之前的问题完全解决。 |
-------
相关文章推荐
- 黑马程序员_自定义异常
- 老程序员应该记住的 5 件事
- 黑马程序员_继承
- 黑马程序员_IO流BufferWriter、BufferReader
- 黑马程序员-java多线程
- Reverse Linked List
- 黑马程序员-Java异常处理机制
- 黑马程序员_MRC2
- 程序员学习能力提升三要素
- 2015(2016届)校园招聘季——百度 篇
- 黑马程序员-Java面向对象
- 培养程序员的人脉
- 2015求职经历
- 武汉软件工程职业学院与传智播客签约达成深度校企合作
- 程序员 应该关注那些事
- [一心想做张江程序员]Infopath设置Develop开发工具集成
- 为什么中国的程序员总被称为码农?
- 腾讯产品总监曹菲:如何克服职业焦虑
- 26种迹象你该考虑辞掉程序员的工作
- 老程序员推荐的 10 个编程策略