多线程(之五:线程协作)

线程通信

  • 应用场景:生产者和消费者问题

    • 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费;
    • 如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止;
    • 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止;
  • 这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。

    • 对于生产者,没有生产产品之前,要通知消费者等待,而生产了产品之后,又需要马上通知消费者消费
    • 对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品用来消费
    • 在生产者消费者问题中,仅有synchronized是不够的
      • synchronized可阻止并发更新同一个共享资源,实现了同步
      • synchronized不能用来实现不同线程之间的消息传递(通信)
  • Java提供了几个方法解决线程之间的通信问题

    方法名 作用
    wait() 表示线程一直等待,真的其他线程通知,也sleep不同,会释放锁
    wait(long timeout) 指定等待的毫秒数
    notify() 唤醒一个处于等待状态的线程
    notifyAll() 唤醒同一个对象上所以调用wait()方法的线程,优先级别高的线程优先调度

    注意:均是Object类的方法,都只能在同步方法或同步代码块中使用,否则会抛出异常lllegalMonitorStateExceptoin

两种解决方式

管程法

并发协作模型“生产者/消费者模式”—>管程法

  • 生产者:负责生产数据的模块(可能是方法,对象,线程,进程)
  • 消费者:负责处理数据的模块(可能是方法,对象,线程,进程)
  • 缓冲区:消费者不能直接使用生产者的数据,他们之间有个“缓冲区”

生产者将产生好的数据放入缓冲区,消费者从缓冲区拿出数据

代码案例
//测试:生产者消费者问题-->利用缓冲区解决-->管程法
public class TestPC {public static void main(String[] args) {SynContainer container = new SynContainer();new Producer(container).start();new Consumer(container).start();}
}//生产者
class Producer extends Thread{SynContainer container;public Producer(SynContainer container){this.container = container;}//生产@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("生产了-->"+i+"只");container.push(new Chicken(i));}}
}//消费者
class Consumer extends Thread{SynContainer container;public Consumer(SynContainer container){this.container = container;}@Overridepublic 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;}
}

信号灯法

  • 使用一个设置一个标志位使用真或者否来判断线程是否进行
代码案例
测试:生产者消费者问题-->利用标志位解决--->信号灯法
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;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {if (i%2==0){this.tv.play("电视剧播放中");}else{this.tv.play("广告播放中");}}}
}//消费者--》观众
class  Watcher extends Thread{TV tv;public Watcher(TV tv){this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {tv.watch();}}
}//产品--》节目
class TV{//演员表演,观众等待 T//观众观看,演员等待 FString voice;//表演的节目boolean flag = true;//表演public synchronized void play(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;}
}

线程池

  • 背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大;
  • 思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具;
  • 好处:
    • 提高响应速度(减少了创建线程的时间)
    • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
    • 方便线程管理
      • corePoolSize:核心池的大小
      • maximumPoolSize:最大线程数
      • keepAliveTime:线程没有任务时最多保持多长时间后会终止

使用线程池

  • JDK5.0起提供了线程池相关API:ExecutorService和Executors

  • ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

    • void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
    • Futuresubmit(Callabletask):执行任务,有返回值,一般用来执行Callable
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池;

代码案例

//测试线程池
public class TextPool {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());//2.关闭连接service.shutdown();}
}
class MyThread implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}

多线程(之五:线程协作)相关推荐

  1. 基于 Java 2 运行时安全模型的线程协作--转

    在 Java 2 之前的版本,运行时的安全模型使用非常严格受限的沙箱模型(Sandbox).读者应该熟悉,Java 不受信的 Applet 代码就是基于这个严格受限的沙箱模型来提供运行时的安全检查.沙 ...

  2. 线程等待通知 linux,Java 线程协作 wait(等待)与 notiy(通知)

    一.wait().notify()和notifyAll() 为了更好的支持多线程之间的协作,JDK提供了三个重要的本地方法 //调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对 ...

  3. java基础提升(二):多线程、线程安全、线程状态、等待唤醒机制、线程池

    目录 一. 多线程 1.1并发与并行 1.2 线程与进程 1.3 创建线程类 1.3.1 方式一:继承Thread类 1.3.2 方式二:实现Runnable接口 1.3.3 Thread和Runna ...

  4. 11_张孝祥_多线程_线程锁技术

    转载 Java并发编程:Lock locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---AbstractOwnableSynchroniz ...

  5. 深入浅出吃透多线程、线程池核心原理及代码详解

    一.多线程详解 1.什么是线程 线程是一个操作系统概念.操作系统负责这个线程的创建.挂起.运行.阻塞和终结操作.而操作系统创建线程.切换线程状态.终结线程都要进行CPU调度--这是一个耗费时间和系统资 ...

  6. Java多线程之线程同步机制(锁,线程池等等)

    Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...

  7. GPU编程自学5 —— 线程协作

    深度学习的兴起,使得多线程以及GPU编程逐渐成为算法工程师无法规避的问题.这里主要记录自己的GPU自学历程. 目录 <GPU编程自学1 -- 引言> <GPU编程自学2 -- CUD ...

  8. 线程协作与生产者消费者问题

    目录 线程协作 生产者和消费者问题 案例-面包店 说明 代码实现 开发面包柜(共享数据资源) 测试代码 线程协作 在多线程开发中,为避免共享资源数据错误,常使用互斥(synchronized)机制实现 ...

  9. 5、Java并发性和多线程-相同线程

    以下内容转自http://tutorials.jenkov.com/java-concurrency/same-threading.html(使用谷歌翻译): 相同线程(同一线程)是一种并发模型,其中 ...

最新文章

  1. Alibaba代码规范插件、FindBugs插件安装及详解,IDEA插件安装,代码规范,代码查错,代码格式规范
  2. 从人人网抓取高校数据信息,包括,省份 - 高校 - 院系 (提供最终SQL文件下载)...
  3. C#的变迁史03 - C# 3.0篇
  4. 盘点多数企业容易犯的五个大数据错误
  5. 在React的render方法中使用箭头函数
  6. Cinesamples CineOrch for Mac(电影管弦乐队音色库)v2.0特别版
  7. javascript笔记—— call 简单理解
  8. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_2-6.Mysql逆向工程效率神器之使用IDE自动生成Java实体类...
  9. Rust: 如何在Windows下Atom中配置Rust环境?
  10. npm升级所有可更新包
  11. python 英文语义分析_python语意分析
  12. 小米手机开发者选项在哪?小米手机怎么打开开发者选项
  13. TouchGFX如何校准电阻触摸屏
  14. win10打开计算机加载很慢,解析为何win10系统中我的电脑打开速度很慢
  15. 内存稳定性测试软件(MemTest)
  16. 云服务器测速脚本_Superspeed.sh:包含很多个测速节点的 VPS 一键测速脚本
  17. 采用DotAsterisk(点星PBX)系统组建跨地区总公司和分公司之间的免费VoIP电话呼叫
  18. 教育部:三年来各省份向校园足球累计投入200亿元
  19. 简单的小青蛙跳一跳问题
  20. 阿里云人脸识别C#调用示例参考

热门文章

  1. 前端开发:webstorm永久破解
  2. NAT与NAT穿透(二)
  3. 什么是Mybatis?Mybatis能干什么?Mybatis怎么配置?
  4. C#通过TCP实现 HL7医疗系统传输的协议,并使用MLLP协议发送HL7消息
  5. MYSQL数据库更改目录及NAVACATamp;nbs…
  6. 行星齿轮传动电动滚筒设计【设计说明书(论文)+11张CAD图纸】
  7. mac os 系统升级到 Catalina 版本后出现应用打不开 ,闪退,意外退出问题
  8. 技术控必读 从Type-A到Type-C发展历程
  9. mencoder 和ffmpeg常用命令
  10. 批处理备份及删除,forfiles命令详解