线程间的通信 与 线程池

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

“管程法” 代码示例:

  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 }

运行结果:

原文地址:https://www.cnblogs.com/huolongluo/p/11810641.html

时间: 2024-10-13 13:05:29

线程间的通信 与 线程池的相关文章

VC++多线程编程-线程间的通信和线程同步

引用:http://blog.csdn.net/zjc0888/article/details/7372258 线程间通讯 一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信.这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明. 使用全局变量进行通信 由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量.对于标准类型

线程间的通信 共享数据安全问题

1 //线程间的通信:线程的任务不同,但是线程操作的数据相同. 2 3 //描述数据 4 class Resource 5 { 6 public String name; 7 public String gender; 8 public Resource(){} 9 } 10 11 //描述输入任务 12 class Input implements Runnable 13 { 14 private Resource res; 15 public Input(Resource res) 16 {

Java基础教程:多线程基础(2)——线程间的通信

Java基础教程:多线程基础(2)--线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 思维导图 等待中 等待/通知机制 不使用等待/通知机制 我们可以使用使用sleep()与 whle(true) 死循环来实现多个线程间的通信. 虽然两个线程实现了通信,但是线程B必须不断的通过while语句轮训机制来检测某一个条件,这样会浪费CPU资源. 如果轮询间隔较小,更浪费时间间隔.如果轮训

线程(二)__线程间的通信

线程间的通信:多个线程在处理同一资源,但是任务却不同.一.等待唤醒机制涉及的方法:1.wait();让线程处于冻结状态,被wait的线程会被存储到线程池中2.notify();唤醒线程池中的一个任意线程3.notifyAll();唤醒线程池中的所有线程这些方法都必须定义在同步中,因为这些方法是用于操作线程状态的方法,必须要明确到底操作的是哪个锁上的线程wait()对A锁上面的线程进行操作后只能用A锁的notify来唤醒.被wait之后的线程可认为放在线程池中. 为什么操作线程的方法wait no

java多线程详解(6)-线程间的通信wait及notify方法

Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New):线程对象已经产生,但尚未被启动,所以无法执行.如通过new产生了一个线程对象后没对它调用start()函数之前.(2). 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它. 当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它

【转】Java学习---线程间的通信

[原文]https://www.toutiao.com/i6572378564534993415/ 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: 这里主要用到了两个内容 1)创建一个标记 flag,让程序进行判断: 当flag != 1 时,print1 进入等待,执行 print2,然后让 flag=1,唤醒正在等待·的线程, 当flag != 0 时,print2 进入等待,执行 print1 ,让后让 flag=0,唤醒正在等待的线程. 2)在

线程间的通信、同步方式与进程间通信方式

1.线程间的通信方式 1)使用全局变量(由于多个线程可能更改全局变量,因此全局变量最好声明为volatile) 2) 使用消息实现通信 3)使用事件CEvent类实现线程间的通信 2.同步/异步(C端) 同步:在C端发出一个功能调用时,没有得到结果之前就不返回 异步: 一个请求通过事件触发后,得到服务器处理后才处理完毕 3. 阻塞/非阻塞(S端) 阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行).函数只有在得到

新建线程与UI线程间的通信

现在用一个实例来演示一下自己的新建线程与UI线程间的通信. UI界面包含3个控件: 一个输入框,用来输入数字: 一个显示框,用来显示从2开始,到输入数字之间的所有质数: 一个按钮,点击后获取输入框输入的数字,交给新建线程处理,线程计算质数后把结果传给UI线程,UI线程显示结果到显示框. XML如下: 1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android=&q

网络开始---多线程---线程间的通信(掌握)(五)

1 #import "HMViewController.h" 2 3 @interface HMViewController () 4 @property (weak, nonatomic) IBOutlet UIImageView *imageView; 5 @end 6 7 @implementation HMViewController 8 9 - (void)viewDidLoad 10 { 11 [super viewDidLoad]; 12 // Do any additi