多线程的等待唤醒机制和Lock锁
2014-10-21 07:19
330 查看
多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。
等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?
因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。
经过分析,发现,产生这种状况的根源是:
1,本方唤醒了本方。
2,被唤醒的本方没有判断标记。
为此,我们要做的改进是——将if 判断改为 while 标记,保证,每次被wait的线程在醒了之后,都得再次判断标记。进过修改,再次运行之后,会发现新的问题又来了,产生了死锁。经过分析,这个问题的根源在于,本方唤醒了本方,被唤醒的本方判断标记后,发现,标记不成立,就继续等待,因此,再也没有活着的线程。为此,我们需要唤醒,所有的线程,就用到了 notifyAll() 。将线程池中,所有等待的线程都叫醒。
经过修改后的代码成功的解决了上述的问题。
Lock:比同步函数和同步代码块要好一些。同步函数还是同步代码块所做的都是隐式的锁操作。并且,同步函数或者同步代码块使用的锁和监视器是同一个。
Lock接口:是将锁进行单独对象的封装。而且提供了对锁对象很多功能。 比如:lock()获取锁,unlock()释放锁。 Lock对锁的操作都是显示操作。所以它的出现要比同步函数或者同步代码块明确的多,更符合面向对象思想。
简单一句话:Lock接口的出现替代同步。
------- android培训、java培训、IOS培训、.Net培训期待与您交流!
----------
等待唤醒机制所涉及到的方法:
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?
因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。
01.public class Resource { 02. private String name; 03. private int count = 1; 04. private boolean flag ; 05. 06. public synchronized void set(String name){ 07. if(flag){ 08. try { 09. this.wait(); 10. } catch (InterruptedException e) { 11. // TODO Auto-generated catch block 12. e.printStackTrace(); 13. } 14. } 15. this.name = name + count; 16. count++; 17. 18. System.out.println(Thread.currentThread().getName() 19. + "The producer name is :++++++++++++++ " + this.name); 20. 21. flag = true; 22. 23. this.notify(); 24. 25. } 26. 27. public synchronized void out(){ 28. if(!flag){ 29. try { 30. this.wait(); 31. } catch (InterruptedException e) { 32. // TODO Auto-generated catch block 33. e.printStackTrace(); 34. } 35. } 36. System.out.println(Thread.currentThread().getName() + 37. "The consumer name is : ---------------------------" + this.name); 38. flag = false; 39. 40. this.notify(); 41. 42. } 43. 44.} 45. 46.public class Producer implements Runnable { 47. 48. private Resource r; 49. public Producer(Resource r){ 50. this.r = r; 51. } 52. @Override 53. public void run() { 54. 55. while(true){ 56. r.set("馒头"); 57. } 58. 59. } 60.} 61. 62.public class Consumer implements Runnable { 63. 64. private Resource r; 65. public Consumer(Resource r ){ 66. this.r = r; 67. } 68. @Override 69. public void run() { 70. 71. while(true){ 72. r.out(); 73. } 74. } 75.} 76. 77.public class ProConDemo { 78. 79. public static void main(String[] args) { 80. 81. //资源对象 82. Resource r = new Resource(); 83. //任务对象 84. Producer pro = new Producer(r); 85. Consumer con = new Consumer(r); 86. //线程对象,两个生产者,两个消费者 87. Thread t1 = new Thread(pro); 88. Thread t2 = new Thread(pro); 89. 90. Thread t3 = new Thread(con); 91. Thread t4 = new Thread(con); 92. 93. //开启线程 94. t1.start(); 95. t2.start(); 96. t3.start(); 97. t4.start(); 98. } 99. 100.}
经过分析,发现,产生这种状况的根源是:
1,本方唤醒了本方。
2,被唤醒的本方没有判断标记。
为此,我们要做的改进是——将if 判断改为 while 标记,保证,每次被wait的线程在醒了之后,都得再次判断标记。进过修改,再次运行之后,会发现新的问题又来了,产生了死锁。经过分析,这个问题的根源在于,本方唤醒了本方,被唤醒的本方判断标记后,发现,标记不成立,就继续等待,因此,再也没有活着的线程。为此,我们需要唤醒,所有的线程,就用到了 notifyAll() 。将线程池中,所有等待的线程都叫醒。
经过修改后的代码成功的解决了上述的问题。
01.public class Resource { 02. private String name; 03. private int count = 1; 04. private boolean flag ; 05. 06. public synchronized void set(String name){ 07. //用while 确保线程醒了后再次,判断标记。 08. while(flag){ 09. try { 10. this.wait(); 11. } catch (InterruptedException e) { 12. // TODO Auto-generated catch block 13. e.printStackTrace(); 14. } 15. } 16. this.name = name + count; 17. count++; 18. 19. System.out.println(Thread.currentThread().getName() 20. + "The producer name is :++++++++++++++ " + this.name); 21. 22. flag = true; 23. //唤醒所有被等待的线程 24. this.notifyAll(); 25. 26. } 27. 28. public synchronized void out(){ 29. //用while 确保线程醒了后再次,判断标记。 30. while(!flag){ 31. try { 32. this.wait(); 33. } catch (InterruptedException e) { 34. // TODO Auto-generated catch block 35. e.printStackTrace(); 36. } 37. } 38. System.out.println(Thread.currentThread().getName() + 39. "The consumer name is : ---------------------------" + this.name); 40. flag = false; 41. //唤醒所有被等待的线程 42. this.notifyAll(); 43. 44. } 45.}
Lock:比同步函数和同步代码块要好一些。同步函数还是同步代码块所做的都是隐式的锁操作。并且,同步函数或者同步代码块使用的锁和监视器是同一个。
Lock接口:是将锁进行单独对象的封装。而且提供了对锁对象很多功能。 比如:lock()获取锁,unlock()释放锁。 Lock对锁的操作都是显示操作。所以它的出现要比同步函数或者同步代码块明确的多,更符合面向对象思想。
简单一句话:Lock接口的出现替代同步。
01.class Resource 02.{ 03. 04. private String name; 05. private int count = 1; 06. private boolean flag; 07. //创建一个锁对象。 08. private final Lock lock = new ReentrantLock(); 09. //创建一个生产者的监视器。 10. private Condition producer_con = lock.newCondition(); 11. //创建一个消费者监视器。 12. private Condition consumer_con = lock.newCondition(); 13. 14. public void set(String name)// 15. { 16. //获取锁。 17. lock.lock(); 18. try 19. { 20. 21. while(flag) 22. try{producer_con.await();}catch(InterruptedException e){} 23. this.name = name + count; 24. 25. count++; 26. 27. System.out.println(Thread.currentThread().getName()+".....生产者......"+this.name); 28. flag = true; 29. consumer_con.signal(); 30. } 31. finally 32. { 33. //释放锁。 34. lock.unlock(); 35. } 36. } 37. 38. public void get()// 39. { 40. lock.lock(); 41. try 42. { 43. 44. while(!flag) 45. try{consumer_con.await();}catch(InterruptedException e){} 46. 47. System.out.println(Thread.currentThread().getName()+".........消费者......"+this.name); 48. flag = false; 49. producer_con.signal(); 50. } 51. finally 52. { 53. lock.unlock(); 54. } 55. } 56.}
------- android培训、java培训、IOS培训、.Net培训期待与您交流!
----------
相关文章推荐
- 多线程(6)等待唤醒机制Lock,condition
- 多线程__【线程间通信】【等待唤醒机制】【多生产多消费】【Lock&Condition接口】
- 24 API-多线程(多线程(多线程JDK5Lock锁,生产者消费者等待唤醒机制,定时器),设计模式(设计原则,设计模式(简单工程,工厂方法,单例模式)
- 多线程__【线程间通信】【等待唤醒机制】【多生产多消费】【Lock&Condition接口】
- Java基础 多线程 解决安全问题 等待唤醒机制 Lock Condition interrupt join setPriority yield
- Java多线程四:线程间通信/等待唤醒机制
- java多线程中的生产者与消费者之等待唤醒机制@Version2.0
- JavaSE 多线程 线程间通讯—等待唤醒机制代码优化(背下来)
- Java---18---多线程:等待唤醒机制
- 多线程等待唤醒机制之生产消费者模式
- 多线程(线程间通信-等待唤醒机制及其代码优化)
- java个人学习笔记18(多线程之间通信+等待唤醒机制)
- 14.显式的锁机制,显式的等待唤醒机制--lock和condition
- 线程唤醒多线程之等待唤醒机制线程唤醒
- Java多线程之线程通信生产者消费者模式及等待唤醒机制代码详解
- 多线程等待唤醒机制之生产消费者模式
- 多线程等待唤醒机制之生产消费者模式
- 多线程_生产者消费者之等待唤醒机制代码优化
- 【JavaSE学习笔记】多线程02_Lock,死锁,等待唤醒机制,线程组和线程池,Timer定时器
- 4、多线程(等待唤醒机制)(synchronized & Condition)两种写法