线程间的通信 与 线程池

Posted huolongluo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程间的通信 与 线程池相关的知识,希望对你有一定的参考价值。

技术图片

利用“生产者/消费者模式”去解决线程间的通信问题,这里整理“管程法”与“信号灯法”两种实现方式。

“管程法” 代码示例:

  1 package com.huolongluo.coindemo;
  2 
  3 /**
  4  * Created by 火龙裸 on 2019/11/10.
  5  * desc   : 线程间的通信
  6  * 生产者与消费者模式 -->利用缓冲区解决:管程法
  7  * version: 1.0
  8  */
  9 
 10 //生产者,消费者,产品,缓冲区
 11 public class TestPC {
 12     public static void main(String[] args) {
 13         SynContainer container = new SynContainer();
 14         new Productor(container).start();
 15         new Consumer(container).start();
 16     }
 17 }
 18 
 19 //生产者
 20 class Productor extends Thread {
 21     SynContainer container;
 22 
 23     public Productor(SynContainer container) {
 24         this.container = container;
 25     }
 26 
 27     //生产
 28     @Override
 29     public void run() {
 30         for (int i = 0; i < 100; i++) {
 31             container.push(new Chicken(i));
 32             System.out.println("生产了 " + i + " 只鸡");
 33         }
 34     }
 35 }
 36 
 37 //消费者
 38 class Consumer extends Thread {
 39     SynContainer container;
 40 
 41     public Consumer(SynContainer container) {
 42         this.container = container;
 43     }
 44 
 45     //消费
 46     @Override
 47     public void run() {
 48         for (int i = 0; i < 100; i++) {
 49             System.out.println("消费了第--> " + container.pop().id + " 只鸡");
 50         }
 51     }
 52 }
 53 
 54 //产品
 55 class Chicken {
 56     int id;//产品编号
 57 
 58     public Chicken(int id) {
 59         this.id = id;
 60     }
 61 }
 62 
 63 //缓冲区
 64 class SynContainer {
 65 
 66     //需要一个容器大小
 67     Chicken[] chickens = new Chicken[10];
 68     //容器计数器
 69     int count = 0;
 70 
 71     //生产者放入产品
 72     public synchronized void push(Chicken chicken) {
 73         //如果容器满了,就需要等待消费者消费
 74         if (count == chickens.length) {
 75             //通知消费者消费,生产者等待
 76             try {
 77                 this.wait();
 78             } catch (InterruptedException e) {
 79                 e.printStackTrace();
 80             }
 81         }
 82         //如果没有满,我们就需要丢入产品
 83         chickens[count] = chicken;
 84         count++;
 85 
 86         //可以通知消费者消费了
 87         this.notifyAll();
 88     }
 89 
 90     //消费者消费产品
 91     public synchronized Chicken pop() {
 92         //判断能否消费
 93         if (count == 0) {
 94             //等待生产者生产,消费者等待
 95             try {
 96                 this.wait();
 97             } catch (InterruptedException e) {
 98                 e.printStackTrace();
 99             }
100         }
101 
102         //如果可以消费
103         count--;
104         Chicken chicken = chickens[count];
105 
106         //吃完了,通知生产者生产
107         this.notifyAll();
108         return chicken;
109     }
110 }

 

“信号灯法” 代码示例:

 1 package com.huolongluo.coindemo.morethread;
 2 
 3 /**
 4  * Created by 火龙裸 on 2019/11/10.
 5  * desc   : 测试生产者消费者问题2:信号灯法,标志位解决
 6  * version: 1.0
 7  */
 8 public class TestPc2 {
 9     public static void main(String[] args) {
10         TV tv = new TV();
11         new Player(tv).start();
12         new Watcher(tv).start();
13     }
14 }
15 
16 //生产者-->演员
17 class Player extends Thread {
18     TV tv;
19 
20     public Player(TV tv) {
21         this.tv = tv;
22     }
23 
24     @Override
25     public void run() {
26         for (int i = 0; i < 20; i++) {
27             if (i % 2 == 0) {
28                 this.tv.paly("快乐大本营");
29             } else {
30                 this.tv.paly("抖音:记录美好生活");
31             }
32         }
33     }
34 }
35 
36 //消费者-->观众
37 class Watcher extends Thread {
38     TV tv;
39 
40     public Watcher(TV tv) {
41         this.tv = tv;
42     }
43 
44     @Override
45     public void run() {
46         for (int i = 0; i < 20; i++) {
47             tv.watch();
48         }
49     }
50 }
51 
52 //产品-->节目
53 class TV {
54     //演员表演,观众等待 (flag为T,演员表演)
55     //观众观看,演员等待 (flag为F,演员等待)
56     String voice;//表演的节目
57     boolean flag = true;
58 
59     //表演
60     public synchronized void paly(String voice) {
61         if (!flag) {
62             try {
63                 this.wait();
64             } catch (InterruptedException e) {
65                 e.printStackTrace();
66             }
67         }
68         System.out.println("演员表演了: " + voice);
69         //通知观众观看
70         this.notifyAll();//通知唤醒
71         this.voice = voice;
72         this.flag = !this.flag;
73     }
74 
75     //观看
76     public synchronized void watch() {
77         if (flag) {
78             try {
79                 this.wait();
80             } catch (InterruptedException e) {
81                 e.printStackTrace();
82             }
83         }
84         System.out.println("观众观看了: " + voice);
85         //通知演员表演
86         this.notifyAll();
87         this.flag = !this.flag;
88     }
89 }

 

线程池

技术图片

 

  • JDK5.0起提供了线程池相关API:ExecutorService和Executors
  • ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

    1. void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable

    2. <T>Future<T> submit(Callable<T> task):执行任务,有返回值,一般用来执行Callable

    3. void shutdown():关闭连接池

  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

 

线程池 代码示例:

 1 package com.huolongluo.coindemo;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 /**
 7  * Created by 火龙裸 on 2019/11/10.
 8  * desc   : 线程池
 9  * version: 1.0
10  */
11 public class TestPool {
12     public static void main(String[] args) {
13         //1.创建服务,创建线程池
14         //newFixedThreadPool 参数为:线程池大小
15         ExecutorService service = Executors.newFixedThreadPool(10);
16 
17         //执行
18         service.execute(new MyThread());
19         service.execute(new MyThread());
20         service.execute(new MyThread());
21         service.execute(new MyThread());
22         service.execute(new MyThread());
23 
24         //2.关闭链接
25         service.shutdown();
26     }
27 }
28 
29 class MyThread implements Runnable {
30 
31     @Override
32     public void run() {
33         System.out.println("当前线程:" + Thread.currentThread().getName());
34     }
35 }

运行结果:

技术图片

 

总结:

线程的实现方式,代码示例如下:

 1 package com.huolongluo.coindemo;
 2 
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.FutureTask;
 6 
 7 /**
 8  * Created by 火龙裸 on 2019/11/10.
 9  * desc   :回顾线程的创建
10  * version: 1.0
11  */
12 public class ThreadNew {
13     public static void main(String[] args) {
14         //启动线程 MyThread1
15         new MyThread1().start();
16 
17         //启动线程 MyThread2
18         new Thread(new MyThread2()).start();
19 
20         //启动线程 MyThread3 (通过Callable接口启动线程的方式有很多,这里只简单介绍一种)
21         //FutureTask的构造参数可以是一个Callable接口,也可以是一个Runnable接口
22         FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
23         new Thread(futureTask).start();//FutureTask本身RunnableFuture接口,而RunnableFuture接口又是继承的Runnable接口,所以可以这样启动
24         try {
25             Integer integer = futureTask.get();//通过get()方法获得返回值
26             System.out.println("获得的返回值:" + integer);
27         } catch (ExecutionException e) {
28             e.printStackTrace();
29         } catch (InterruptedException e) {
30             e.printStackTrace();
31         }
32     }
33 }
34 
35 //1.继承Thread类
36 class MyThread1 extends Thread {
37     @Override
38     public void run() {
39         System.out.println("Thread1");
40     }
41 }
42 
43 //2.实现Runnable接口
44 class MyThread2 implements Runnable {
45 
46     @Override
47     public void run() {
48         System.out.println("MyThread2");
49     }
50 }
51 
52 //3.实现Callable接口
53 class MyThread3 implements Callable<Integer> {
54     @Override
55     public Integer call() throws Exception {
56         System.out.println("MyThread3");
57         return 100;
58     }
59 }

运行结果:

技术图片

以上是关于线程间的通信 与 线程池的主要内容,如果未能解决你的问题,请参考以下文章

java-等待唤醒机制(线程中的通信)-线程池

多线程-线程间的通信

多线程-线程间的通信

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

多线程---线程间的通信

RTX 线程通信之——内存池