java多线程--7 线程协作 线程池

并发协作模型--生产者消费者模式

这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间互相依赖,互为条件。

java提供了几个方法解决线程之间的通信问题

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

注意:

  • 以上均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException

两种解决方法

管程法

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

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

package com.ssl.demo06;

//管程法解决生产者消费者模型---》利用缓冲区解决
//需要生产者、消费者、产品、缓冲区
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) {
throw new RuntimeException(e);
}
}
//如果没有满,我们就放入产品
chickens[count]=chicken;
count++;
//可以通知消费者消费了
this.notifyAll();
} //消费者消费产品
public synchronized Chicken pop(){
//判断是否能消费
if(count==0){
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} //消费
count--;
Chicken chicken = chickens[count]; //通知生产者,吃完了
this.notifyAll(); return chicken;
} }

信号灯法

package com.ssl.demo06;

//信号灯法解决生产者消费者问题,标志位解决
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.play("电视剧");
}else {
this.tv.play("广告");
}
}
}
}
//消费者--》观众
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{
//演员表演,观众等待
//观众观看,演员等待
String voice; //表演的节目
boolean flag = true; //表演
public synchronized void play(String voice){
if(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("演员表演了"+voice);
this.voice =voice;
this.flag = !this.flag;
//通知观众观看
this.notifyAll();
} //观看
public synchronized void watch(){
if(flag) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("观看了"+this.voice); this.flag = !this.flag;
//通知演员表演
this.notifyAll(); }
}

线程池

  • 思路:提前创造好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁的创建销毁,实现重复利用。

  • 好处

    • 提高响应速度(减少了创建新线程的时间)
    • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
    • 便于线程管理(....)
      • corePoolSize:核心池的大小
      • maximumPoolSize:最大线程数
      • keepAliveTime: 线程没有任务时最多保持多长时间后终止
  • JDK5 提供了线程池相关的API ExecutorService 和 Executors

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

      • void execute(Runnable command): 执行任务/命令,没有返回值,一般用来执行Runnable
      • Future submit( task):执行任务,有返回值,一般用来执行Callable
      • void shutdown():关闭连接池
    • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池。
package com.ssl.demo06;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; //测试线程池
public class TestPool {
public static void main(String[] args) { //1.创建线程池
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{ @Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}

java多线程--7 线程协作 线程池的更多相关文章

  1. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

  2. Java多线程(一) —— 线程的状态详解

    一.多线程概述  1. 进程 是一个正在执行的程序.是程序在计算机上的一次运行活动. 每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 系统以进程为基本单位进行系统资源的调度 ...

  3. Java多线程(五)线程的生命周期

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  4. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  5. java多线程总结五:线程池的原理及实现

    1.线程池简介:     多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.        假设一个服务器完成一项任务所需时间为:T1 创 ...

  6. java多线程(四)-自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...

  7. java多线程系列六、线程池

    一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池. 2. 使用线程池的好处 a) 降低资源的消耗.使用线程池不用频繁的创建线程和销毁线程 b) 提高响应速度,任 ...

  8. Java多线程面试题:线程锁+线程池+线程同步等

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

  9. (Java多线程系列九)线程池

    线程池 1.什么是线程池 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程.线程池中线程的数量通常取决于可用内存数量和应用程序的需求. ...

  10. Java多线程并发04——合理使用线程池

    在此之前,我们已经了解了关于线程的基本知识,今天将为各位带来,线程池这一技术.关注我的公众号「Java面典」了解更多 Java 相关知识点. 为什么使用线程池?线程池做的工作主要是控制运行的线程的数量 ...

随机推荐

  1. CCIE DC Multicast Part 1.

    Hi Guys! As we all wait anxiously for the training vendors to release Rack Rentals (Come on guys! At ...

  2. pycharm开发工具的介绍和使用

    pycharm开发工具的介绍和使用 PyCharm是常用的python开发工具之一,分为社区版和专业版,社区版只有基础的python环境,专业版的功能会多很多

  3. appium程序下载安装/appium desktop

    官网地址:http://appium.io/ 点击下载按钮 默认跳转到最新版本,点击 Releases 回到版本列表页 该页可以看到对应的版本及更新时间,(最好不要下载最新版本) 如果是 Window ...

  4. ssh连接不上、Xshell意外关闭Socket error Event: 32 Error: 10053.

    Xshell意外关闭可能会出现这种问题,如遇如下错误可解决: Connecting to 47.106.80.28:22- Connection established. To escape to l ...

  5. MQTT服务器搭建——Liunx安装mosquitto,并设置用户密码

    一.安装 1.下载mosquitto安装包 地址:http://mosquitto.org/files/source/ 2.安装依赖包 yum install gcc gcc-c++ libstdc+ ...

  6. OO课程第三阶段(实验和pta试题)总结Blog3

    OO课程第三阶段(实验和pta试题)总结Blog3 前言:学习OOP课程的第三阶段已经结束了,在此进行对于知识点,题量,难度的个人看法. 学习OOP课程的第三阶段已经结束了,较第一次阶段学习难度加大, ...

  7. DataRow[]数组转换为DataTable

    DataRow[] drData=DataTable.Select("....."); DataTable dtNew=drData.CopyToDataTable(); 注:Da ...

  8. CAD2023卸载方法,如何完全彻底卸载删除清理干净cad各种残留注册表和文件?【转载】

    cad2023卸载重新安装方法,使用清理卸载工具箱完全彻底删除干净cad2023各种残留注册表和文件.cad2023显示已安装或者报错出现提示安装未完成某些产品无法安装的问题,怎么完全彻底删除清理干净 ...

  9. 无线电(手台、APRS)

    泉胜手台操作:(TG-UV2)----------------------------------------------- MR/VFO: 频率模式指示F:信道模式指示M F+MAIN: 主副频转换 ...

  10. api进阶Day3使用文件流对文件进行复制、使用块读写一组字节,使用byte数组提高读写的效率、返回当前时间。

    使用文件流对文件进行复制: package io; import java.io.FileInputStream; import java.io.FileNotFoundException; impo ...