利用 "生产者 / 消费者模式" 去解决线程间的通信问题, 这里整理 "管程法" 与 "信号灯法" 两种实现方式.
"管程法" 代码示例:
- package com.huolongluo.coindemo;
- /**
- * Created by 火龙裸 on 2019/11/10.
- * desc : 线程间的通信
- * 生产者与消费者模式 --> 利用缓冲区解决: 管程法
- * version: 1.0
- */
- // 生产者, 消费者, 产品, 缓冲区
- public class TestPC {
- public static void main(String[] args) {
- SynContainer container = new SynContainer();
- new Productor(container).start();
- new Consumer(container).start();
- }
- }
- // 生产者
- class Productor extends Thread {
- SynContainer container;
- public Productor(SynContainer container) {
- this.container = container;
- }
- // 生产
- @Override
- public void run() {
- for (int i = 0; i <100; i++) {
- container.push(new Chicken(i));
- System.out.println("生产了" + i + "只鸡");
- }
- }
- }
- // 消费者
- class Consumer extends Thread {
- SynContainer container;
- public Consumer(SynContainer container) {
- this.container = container;
- }
- // 消费
- @Override
- public void run() {
- for (int i = 0; i < 100; i++) {
- System.out.println("消费了第 -->" + container.pop().id + "只鸡");
- }
- }
- }
- // 产品
- class Chicken {
- int id;// 产品编号
- public Chicken(int id) {
- this.id = id;
- }
- }
- // 缓冲区
- class SynContainer {
- // 需要一个容器大小
- Chicken[] chickens = new Chicken[10];
- // 容器计数器
- int count = 0;
- // 生产者放入产品
- public synchronized void push(Chicken chicken) {
- // 如果容器满了, 就需要等待消费者消费
- if (count == chickens.length) {
- // 通知消费者消费, 生产者等待
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- // 如果没有满, 我们就需要丢入产品
- chickens[count] = chicken;
- count++;
- // 可以通知消费者消费了
- this.notifyAll();
- }
- // 消费者消费产品
- public synchronized Chicken pop() {
- // 判断能否消费
- if (count == 0) {
- // 等待生产者生产, 消费者等待
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- // 如果可以消费
- count--;
- Chicken chicken = chickens[count];
- // 吃完了, 通知生产者生产
- this.notifyAll();
- return chicken;
- }
- }
"信号灯法" 代码示例:
- package com.huolongluo.coindemo.morethread;
- /**
- * Created by 火龙裸 on 2019/11/10.
- * desc : 测试生产者消费者问题 2: 信号灯法, 标志位解决
- * version: 1.0
- */
- public class TestPc2 {
- public static void main(String[] args) {
- TV tv = new TV();
- new Player(tv).start();
- new Watcher(tv).start();
- }
- }
- // 生产者 --> 演员
- class Player extends Thread {
- TV tv;
- public Player(TV tv) {
- this.tv = tv;
- }
- @Override
- public void run() {
- for (int i = 0; i <20; i++) {
- if (i % 2 == 0) {
- this.tv.paly("快乐大本营");
- } else {
- this.tv.paly("抖音: 记录美好生活");
- }
- }
- }
- }
- // 消费者 --> 观众
- class Watcher extends Thread {
- TV tv;
- public Watcher(TV tv) {
- this.tv = tv;
- }
- @Override
- public void run() {
- for (int i = 0; i <20; i++) {
- tv.watch();
- }
- }
- }
- // 产品 --> 节目
- class TV {
- // 演员表演, 观众等待 (flag 为 T, 演员表演)
- // 观众观看, 演员等待 (flag 为 F, 演员等待)
- String voice;// 表演的节目
- boolean flag = true;
- // 表演
- public synchronized void paly(String voice) {
- if (!flag) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println("演员表演了:" + voice);
- // 通知观众观看
- this.notifyAll();// 通知唤醒
- this.voice = voice;
- this.flag = !this.flag;
- }
- // 观看
- public synchronized void watch() {
- if (flag) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println("观众观看了:" + voice);
- // 通知演员表演
- this.notifyAll();
- this.flag = !this.flag;
- }
- }
线程池
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: 工具类, 线程池的工厂类, 用于创建并返回不同类型的线程池
线程池 代码示例:
- package com.huolongluo.coindemo;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- /**
- * Created by 火龙裸 on 2019/11/10.
- * desc : 线程池
- * version: 1.0
- */
- public class TestPool {
- public static void main(String[] args) {
- //1. 创建服务, 创建线程池
- //newFixedThreadPool 参数为: 线程池大小
- ExecutorService service = Executors.newFixedThreadPool(10);
- // 执行
- service.execute(new MyThread());
- service.execute(new MyThread());
- service.execute(new MyThread());
- service.execute(new MyThread());
- service.execute(new MyThread());
- //2. 关闭链接
- service.shutdown();
- }
- }
- class MyThread implements Runnable {
- @Override
- public void run() {
- System.out.println("当前线程:" + Thread.currentThread().getName());
- }
- }
运行结果:
总结:
线程的实现方式, 代码示例如下:
- package com.huolongluo.coindemo;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.FutureTask;
- /**
- * Created by 火龙裸 on 2019/11/10.
- * desc : 回顾线程的创建
- * version: 1.0
- */
- public class ThreadNew {
- public static void main(String[] args) {
- // 启动线程 MyThread1
- new MyThread1().start();
- // 启动线程 MyThread2
- new Thread(new MyThread2()).start();
- // 启动线程 MyThread3 (通过 Callable 接口启动线程的方式有很多, 这里只简单介绍一种)
- //FutureTask 的构造参数可以是一个 Callable 接口, 也可以是一个 Runnable 接口
- FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
- new Thread(futureTask).start();//FutureTask 本身 RunnableFuture 接口, 而 RunnableFuture 接口又是继承的 Runnable 接口, 所以可以这样启动
- try {
- Integer integer = futureTask.get();// 通过 get() 方法获得返回值
- System.out.println("获得的返回值:" + integer);
- } catch (ExecutionException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- //1. 继承 Thread 类
- class MyThread1 extends Thread {
- @Override
- public void run() {
- System.out.println("Thread1");
- }
- }
- //2. 实现 Runnable 接口
- class MyThread2 implements Runnable {
- @Override
- public void run() {
- System.out.println("MyThread2");
- }
- }
- //3. 实现 Callable 接口
- class MyThread3 implements Callable<Integer> {
- @Override
- public Integer call() throws Exception {
- System.out.println("MyThread3");
- return 100;
- }
- }
运行结果:
来源: http://www.bubuko.com/infodetail-3281137.html