JAVA Review-应用程序开发-JAVA多线程-线程通信

秒速五厘米 2022-05-22 11:04 276阅读 0赞

前言

前面一节中我们学习如何在多线程中确保共享数据的线程安全。本节我们将学一下如何实现多线程间的通信。
首先在JAVA中有很多方式实现多线程间的通信。本节将着重讲学习如何使用synchronized+notify+wait+flag的方式来实现多线程的通信。
首先我们先了解一下一些概念:

  • wait()
  1. * 令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
  • notify()
  1. * 唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
  • notifyAll ()
  1. * 唤醒正在排队等待资源的所有线程结束等待。

wait()、notify()、notifyAll () 只能在synchronized修饰的代码块或者方法中使用!,是多线程通信的独有方法。


示例

我们将通过一些例子来学习java多线程通信。

  • 生产者与消费者
    生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下, 如果店中有产品了再通知消费者来取走产品。

    1. class Clerk{ //店员
    2. int product;
    3. public synchronized void addProduct(){
    4. //生产产品
    5. if(product >= 20){
    6. try {
    7. wait();
    8. } catch (InterruptedException e) {
    9. // TODO Auto-generated catch block
    10. e.printStackTrace();
    11. }
    12. }else{
    13. product++;
    14. System.out.println(Thread.currentThread().getName() + ":生产了第" + product + "个产品");
    15. notifyAll();
    16. }
    17. }
    18. public synchronized void consumeProduct(){
    19. //消费产品
    20. if(product <= 0){
    21. try {
    22. wait();
    23. } catch (InterruptedException e) {
    24. // TODO Auto-generated catch block
    25. e.printStackTrace();
    26. }
    27. }else{
    28. System.out.println(Thread.currentThread().getName() + ":消费了第" + product + "个产品");
    29. product--;
    30. notifyAll();
    31. }
    32. }
    33. }
    34. class Producer implements Runnable{ //生产者
    35. Clerk clerk;
    36. public Producer(Clerk clerk){
    37. this.clerk = clerk;
    38. }
    39. public void run(){
    40. System.out.println("生产者开始生产产品");
    41. while(true){
    42. try {
    43. Thread.currentThread().sleep(100);
    44. } catch (InterruptedException e) {
    45. // TODO Auto-generated catch block
    46. e.printStackTrace();
    47. }
    48. clerk.addProduct();
    49. }
    50. }
    51. }
    52. class Consumer implements Runnable{ //消费者
    53. Clerk clerk;
    54. public Consumer(Clerk clerk){
    55. this.clerk = clerk;
    56. }
    57. public void run(){
    58. System.out.println("消费者消费产品");
    59. while(true){
    60. try {
    61. Thread.currentThread().sleep(10);
    62. } catch (InterruptedException e) {
    63. // TODO Auto-generated catch block
    64. e.printStackTrace();
    65. }
    66. clerk.consumeProduct();
    67. }
    68. }
    69. }
  1. public class produceAndConsumer{
  2. public static void main(String[] args) {
  3. Clerk clerk = new Clerk();
  4. Producer p1 = new Producer(clerk);
  5. Consumer c1 = new Consumer(clerk);
  6. Thread t1 = new Thread(p1);//一个生产者的线程
  7. Thread t2 = new Thread(c1);//一个消费者的线程
  8. t1.setName("生产者1");
  9. t2.setName("消费者1");
  10. t1.start();
  11. t2.start();
  12. }
  13. }

程序设计思路:在上例中,生产者和消费者只负责生产产品和消费产品,至于什么时候(库存>=0)该生产什么时候(0<库存<20)可以消费取决于店员,因而店员将是统一调度生产者生产和消费者消费的关键所在。

  • 两个打印机交替打印

    • 两个打印机交替打印1-100内的整数
    • 代码示例

      1. ```
      2. package coreJavaReview.thread;
      3. class PrintNum implements Runnable {
      4. int num = 1;
      5. Object obj = new Object();
      6. public void run() {
      7. while (true) {
      8. synchronized (obj) {
      9. obj.notify();
      10. if (num <= 100) {
      11. try {
      12. Thread.currentThread().sleep(10);
      13. } catch (InterruptedException e) {
      14. // TODO Auto-generated catch block
      15. e.printStackTrace();
      16. }
      17. System.out.println(Thread.currentThread().getName() + ":"
      18. + num);
      19. num++;
      20. } else {
      21. break;
      22. }
      23. try {
      24. obj.wait();
      25. } catch (InterruptedException e) {
      26. // TODO Auto-generated catch block
      27. e.printStackTrace();
      28. }
      29. }
      30. }
      31. }
      32. }
      33. public class ThreadCommunicationCross {
      34. public static void main(String[] args) {
      35. PrintNum p = new PrintNum();
      36. Thread t1 = new Thread(p);
      37. Thread t2 = new Thread(p);
      38. t1.setName("A");
      39. t2.setName("B");
      40. t1.start();
      41. t2.start();
      42. }
      43. }
      44. ```

      程序设计思路:两台打印机交替打印,每次只能有一台机器在打印,也需要要求是多线程安全的,此时要求获得打印资格的打印机必须在打印完毕之后放弃(放弃CPU资源)打印资格。

    • 多线程按照顺序循环地执行

      • 场景说明
        开启三个线程顺序地执行输出1-150整数。,每个线程持续输出连续的5个整数。
      • 代码示例

        1. package coreJavaReview.thread;
        2. public class ThreadCrossCommunicationTest {
        3. public static void main(String[] args) {
        4. Object obj = new Object();
        5. for(int i=1;i<=3;i++){
        6. //传入对象锁 和 i值
        7. new Thread(new MyThread2(obj,i), "线程"+i).start();
        8. }
        9. }
        10. }
        11. class MyThread2 implements Runnable{
        12. private static int i = 0;//打印的值 1-75
        13. private static int count=0;//计数 三次一轮回
        14. private Object obj;
        15. private int n;//接参 i值
        16. public MyThread2(Object obj,int n) {
        17. this.obj=obj;
        18. this.n = n;
        19. }
  1. @Override
  2. public void run() {
  3. synchronized (obj) {
  4. while(i<150){
  5. //i++ 在代码块 所以到74就可以了
  6. obj.notifyAll();//唤醒所有线程
  7. if(count%3!=(n-1)){ //找出下一个线程 不正确的线程等待
  8. try {
  9. obj.wait();
  10. } catch (InterruptedException e) {
  11. // TODO Auto-generated catch block
  12. e.printStackTrace();
  13. }
  14. }
  15. i++;
  16. System.out.println(Thread.currentThread().getName()+": "+i);
  17. if(i%5 == 0){ //打印了五次后 此线程让出资源,等待
  18. try {
  19. count++; //count是static修饰 ,为了共享
  20. System.out.println();
  21. obj.wait();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }
  27. }
  28. }
  29. }

发表评论

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

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

相关阅读

    相关 Java 线-线通信

    最近,美美非常的爱吃栗子,剥栗子却有些麻烦,这个任务理所当然的交给了帅帅,每一次,帅帅都会把热气腾腾的栗子剥好,然后放进一个盘子里,而美美每次都会从盘子里拿一个栗子吃: !