thinking in java 05

- 日理万妓 2022-08-21 00:17 316阅读 0赞

线程之间的协作:

只能在同步方法或者同步控制块中调用wait() notify() notifyAll() 否则运行时抛出异常

线程调用sleep() yield()时 线程上的锁没有释放,调用wait()时 线程被挂起 锁释放

使用notify()而不是notifyAll()是一种优化

使用notify()的限制 :1 .所有任务必须等待相同的条件

  1. 2. 当条件变化时,必须只有一个任务从中受益

notifyAll()因某个特定锁调用时,只能等待这个锁的任务才会被唤醒

而这个锁与底层锁有关。

具体代码如下:

  1. package Number_2103;
  2. import java.util.Timer;
  3. import java.util.TimerTask;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.TimeUnit;
  7. /**
  8. * notifyAll() 只能唤醒特定锁 wait()的线程
  9. * 该特定锁与底层对象有关 ---->
  10. *
  11. * @author he
  12. *
  13. */
  14. class Blocker {
  15. synchronized void waitingforCall() {
  16. try {
  17. while (!Thread.interrupted()) {
  18. wait();
  19. System.out.println(Thread.currentThread().hashCode() + "----");
  20. }
  21. } catch (InterruptedException e) {
  22. // TODO Auto-generated catch block
  23. e.printStackTrace();
  24. }
  25. }
  26. synchronized void prod() {
  27. notify();
  28. }
  29. synchronized void prodAll() {
  30. notifyAll();
  31. }
  32. }
  33. class Task implements Runnable {
  34. static Blocker b1;
  35. public Task(Blocker b) {
  36. b1 = b;
  37. }
  38. public synchronized void run() {
  39. // TODO Auto-generated method stub
  40. b1.waitingforCall();
  41. }
  42. }
  43. class Task2 implements Runnable {
  44. static Blocker b2;
  45. public Task2(Blocker b) {
  46. b2 = b;
  47. }
  48. public synchronized void run() {
  49. // TODO Auto-generated method stub
  50. b2.waitingforCall();
  51. }
  52. }
  53. public class P707 {
  54. public static void main(String[] args) throws Exception {
  55. ExecutorService eService = Executors.newCachedThreadPool();
  56. Blocker b = new Blocker();
  57. Blocker b2=new Blocker();
  58. eService.execute(new Task(b));
  59. eService.execute(new Task2(b2));
  60. Timer t = new Timer();
  61. t.schedule(new TimerTask() {
  62. boolean pro = true;
  63. @Override
  64. public void run() {
  65. if (pro) {
  66. Task.b1.prod();
  67. pro = false;
  68. } else {
  69. Task.b1.prodAll();
  70. pro = true;
  71. }
  72. }
  73. }, 400, 400);
  74. TimeUnit.SECONDS.sleep(5);
  75. ;
  76. t.cancel();
  77. System.out.println(" timer cancled");
  78. TimeUnit.MICROSECONDS.sleep(500);
  79. Task2.b2.prodAll();
  80. TimeUnit.MICROSECONDS.sleep(5000);
  81. System.out.println("Shutting down");
  82. eService.shutdown();
  83. }
  84. }

代码分析:public void run() {
if (pro) {
Task.b1.prod();
pro = false;
} else {
Task.b1.prodAll();
pro = true;
}

}

这段代码中交替调用Task中Blocker对象b1的prod()方法和prodall()方法

但是

  1. Blocker b = new Blocker();
  2. Blocker b2=new Blocker();
  3. eService.execute(new Task(b));
  4. eService.execute(new Task2(b2));

由于Task()中穿的Blocker对象不同,所以此时b1.prodall()并不能唤醒task2对象

代码结果如下:

2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
2059770520——
timer cancled
1824109660——
Shutting down

-———————————————————————————————————

如果将代码

  1. Blocker b = new Blocker();
  2. Blocker b2=new Blocker();
  3. eService.execute(new Task(b));
  4. eService.execute(new Task2(b2));

改为:

  1. eService.execute(new Task(b));

eService.execute(new Task2(b));

代码结果如下:

2059770520——
2059770520——
1824109660——
2059770520——
2059770520——
1824109660——
2059770520——
2059770520——
1824109660——
2059770520——
2059770520——
1824109660——
2059770520——
2059770520——
1824109660——
2059770520——
2059770520——
1824109660——
timer cancled
1824109660——
2059770520——
Shutting down

-——————————————————————-

由于 task 和task2 中传的是相同的Blocker对象具有相同的底层锁

此时 此时b1.prodall()能唤醒task2对象

task2.b2.prodall()也能唤醒task对象

使用同步队列进行同步控制 LinkedBlockingQueue 无界 ArrayBlockingQueue 有固定大小

  1. package Number_2103;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.LinkedBlockingQueue;
  5. import java.util.concurrent.TimeUnit;
  6. import Number_2103.Toast.Status;
  7. /**
  8. * 使用同步队列进行同步控制 LinkedBlockingQueue 无界 ArrayBlockingQueue 有固定大小
  9. *
  10. * @author he
  11. *
  12. */
  13. class Toast {
  14. public enum Status {
  15. DRY, BUTTERED, JAMMED
  16. }
  17. private static Status status = Status.DRY;
  18. private final int id;
  19. public Toast(int id) {
  20. this.id = id;
  21. }
  22. public void butter() {
  23. status = Status.BUTTERED;
  24. }
  25. public void jam() {
  26. status = Status.JAMMED;
  27. }
  28. public int getId() {
  29. return id;
  30. }
  31. public static Status getStatus() {
  32. return status;
  33. }
  34. @Override
  35. public String toString() {
  36. // TODO Auto-generated method stub
  37. return "Toast" + id + ":" + status;
  38. }
  39. }
  40. class ToastQueue extends LinkedBlockingQueue<Toast> {
  41. }
  42. class Toaster implements Runnable {
  43. ToastQueue toastDry;
  44. private int count = 0;
  45. public Toaster(ToastQueue t) {
  46. toastDry = t;
  47. }
  48. public void run() {
  49. try {
  50. while (!Thread.interrupted()) {
  51. Toast t = new Toast(count++);
  52. System.out.println(t);
  53. toastDry.put(t);
  54. }
  55. } catch (Exception e) {
  56. // TODO: handle exception
  57. }
  58. System.out.println("Toaster off");
  59. }
  60. }
  61. class ToastButter implements Runnable {
  62. ToastQueue dryToast, butterToast;
  63. public ToastButter(ToastQueue dry, ToastQueue butter) {
  64. dryToast = dry;
  65. butterToast = butter;
  66. }
  67. public void run() {
  68. try {
  69. while (!Thread.interrupted()) {
  70. // 获取并移除头部,在元素变得可用之前一直等待
  71. Toast t = dryToast.take();
  72. t.butter();
  73. System.out.println(t);
  74. butterToast.put(t);
  75. }
  76. } catch (Exception e) {
  77. // TODO: handle exception
  78. }
  79. System.out.println("Butter off");
  80. }
  81. }
  82. class ToastJam implements Runnable {
  83. ToastQueue butt, jam;
  84. public ToastJam(ToastQueue buf, ToastQueue j) {
  85. butt = buf;
  86. jam = j;
  87. }
  88. public void run() {
  89. try {
  90. while (!Thread.interrupted()) {
  91. Toast t = butt.take();
  92. t.jam();
  93. System.out.println(t);
  94. jam.put(t);
  95. }
  96. } catch (Exception e) {
  97. // TODO: handle exception
  98. }
  99. System.out.println("Jam off");
  100. }
  101. }
  102. class Eater implements Runnable {
  103. private ToastQueue fin;
  104. private int count = 0;
  105. public Eater(ToastQueue t) {
  106. fin = t;
  107. }
  108. public void run() {
  109. try {
  110. while (!Thread.interrupted()) {
  111. Toast t = fin.take();
  112. if (t.getId() != count++ || t.getStatus() != Status.JAMMED) {
  113. System.out.println("Error" + t);
  114. System.exit(0);
  115. }
  116. else{
  117. System.out.println("Chomp "+t);
  118. }
  119. }
  120. } catch (Exception e) {
  121. // TODO: handle exception
  122. }
  123. }
  124. }
  125. public class P716 {
  126. public static void main(String[] args) throws Exception {
  127. ExecutorService eService = Executors.newCachedThreadPool();
  128. ToastQueue dryQueue = new ToastQueue();
  129. ToastQueue butterQueue = new ToastQueue();
  130. ToastQueue jamQueue = new ToastQueue();
  131. eService.execute(new Toaster(dryQueue));
  132. eService.execute(new ToastButter(dryQueue, butterQueue));
  133. eService.execute(new ToastJam(butterQueue, jamQueue));
  134. eService.execute(new Eater(jamQueue));
  135. TimeUnit.MILLISECONDS.sleep(1);
  136. eService.shutdownNow();
  137. }
  138. }

生产者与消费者:

  1. package Number_2103;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.TimeUnit;
  5. /**
  6. * P709 生产者与消费者
  7. *
  8. * @author he
  9. *
  10. */
  11. class Meal {
  12. private final int count;
  13. public Meal(int count) {
  14. this.count = count;
  15. }
  16. @Override
  17. public String toString() {
  18. return "Meal " + count;
  19. }
  20. }
  21. class WaitPerson implements Runnable {
  22. private Restaurant restaurant;
  23. public WaitPerson(Restaurant r) {
  24. restaurant = r;
  25. }
  26. public void run() {
  27. try {
  28. while (!Thread.interrupted()) {
  29. synchronized (this) {
  30. while (restaurant.meal == null) {
  31. wait();
  32. }
  33. }
  34. System.out.println("WaitPerson got:" + restaurant.meal);
  35. synchronized (restaurant.chef) {
  36. restaurant.meal = null;
  37. restaurant.chef.notifyAll();
  38. }
  39. }
  40. } catch (InterruptedException e) {
  41. System.out.println("WaitPerson interruped");
  42. }
  43. }
  44. }
  45. class Chef implements Runnable {
  46. private Restaurant restaurant;
  47. private int count = 0;
  48. public Chef(Restaurant r) {
  49. restaurant = r;
  50. }
  51. public void run() {
  52. try {
  53. while (!Thread.interrupted()) {
  54. synchronized (this) {
  55. while (restaurant.meal != null) {
  56. wait();
  57. }
  58. }
  59. if (++count == 10) {
  60. System.out.println("停止出售");
  61. restaurant.eService.shutdownNow();
  62. }
  63. TimeUnit.MICROSECONDS.sleep(100);
  64. System.out.print("Order up");
  65. synchronized (restaurant.waitPerson) {
  66. restaurant.meal = new Meal(count);
  67. // 唤醒服务员线程
  68. restaurant.waitPerson.notifyAll();
  69. }
  70. }
  71. } catch (InterruptedException e) {
  72. System.out.println("退出线程");
  73. }
  74. }
  75. }
  76. public class Restaurant {
  77. Meal meal;
  78. WaitPerson waitPerson = new WaitPerson(this);
  79. Chef chef = new Chef(this);
  80. ExecutorService eService = Executors.newCachedThreadPool();
  81. public Restaurant() {
  82. eService.execute(chef);
  83. eService.execute(waitPerson);
  84. }
  85. public static void main(String[] args) {
  86. new Restaurant();
  87. }
  88. }

发表评论

表情:
评论列表 (有 0 条评论,316人围观)

还没有评论,来说两句吧...

相关阅读

    相关 thinking in java 04

    线程的状态:                                       1.新建(new)  :分配了系统必要的资源,并执行了初始化,有资格获得CPU时间了

    相关 Thinking in java(八)

    正则表达式 正则表达式符号介绍:正则表达式一般也需要使用字符串进行展示: 1、一般符号 x: 指的是普通字符,x代表的是未知数,代表着任何一个普通字符,举例x可以

    相关 Think in Java——复用类

    复用类方法 Java复用代码的思路有两种: 组合:在新类中产生现有类的对象,再添加新的扩展成员与行为; 继承:新类继承自现有类,拥有现有类的全部特性。 组

    相关 thinking in java 笔记

    1,多态,向上转型:解决的办法是后期绑定,它的含义就是在运行时根据对象的类型进行绑定。后期绑定也叫动态绑定或运行时绑定。 java中除了static方法和final方法,(p

    相关 Think in Java——多态

    多态调用 1. 将 一个方法调用 和 一个方法主体 关联起来被称作绑定。绑定分为前期绑定与后期绑定,多态方法的具体调用依靠前期绑定是不行的,编译器不知道对象的具体类型无