java多线程(11):线程协作

news2024/9/23 11:27:25

1 线程通信

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

假设仓库中只能存放一件产品 , 生产者将生产出来的产品放入仓库 , 消费者将仓库中产品取走消费 

如果仓库中没有产品 , 则生产者将产品放入仓库 , 否则停止生产并等待 , 直到仓库中的产品被消费者取走为止 

如果仓库中放有产品 , 则消费者可以将产品取走消费 , 否则停止消费并等待 , 直到仓库中再次放入产品为止 

2 线程通信分析

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

对于生产者 , 没有生产产品之前 , 要通知消费者等待 ,而生产了产品之后 , 又需要马上通知消费者消费 

对于消费者 , 在消费之后 , 要通知生产者已经结束消费 , 需要生产新的产品以供消费

在生产者消费者问题中 , 仅有synchronized是不够的 

synchronized 可阻止并发更新同一个共享资源 , 实现了同步 

synchronized 不能用来实现不同线程之间的消息传递 (通信)

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

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

3 解决方式1

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

生产者 : 负责生产数据的模块 (可能是方法 , 对象 , 线程 , 进程) ; 

消费者 : 负责处理数据的模块 (可能是方法 , 对象 , 线程 , 进程) ; 

缓冲区 : 消费者不能直接使用生产者的数据 , 他们之间有个 “ 缓冲区 

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

下面以生产鸡为例:

定义鸡的实体

package xiong.demo6;

public class Chicken {
    int id;
    public Chicken(int id){
        this.id = id;
    }
}

生产和消费都在缓冲区进行

package xiong.demo6;

//缓冲区
public class SynContainer {
    //需要一个容器大小
    Chicken[] chickens = new Chicken[10];
    //容器计数器
    int count = 0;

    //生产者放入产品
    public synchronized void push(Chicken chicken){
        //如果容器满了,就需要等待消费者消费
        while (count == chickens.length){
            //生产等待
            try{
                this.wait();
            }catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        //如果没有满。我们就需要丢入产品
        chickens[count++] = chicken;
        this.notify();
    }

    //消费者消费产品
    public synchronized Chicken pop(){
        //判断能否消费
        while(count==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        //吃完了,通知消费者生产
        this.notifyAll();
        return chicken;
    }
}

定义生产者:

package xiong.demo6;

public class Productor extends Thread {
    SynContainer container;
    public Productor (SynContainer container){
        this.container = container;
    }
    //生产
    @Override
    public void run() {
        int i =0;
        while(true){
            i++;
            System.out.println("生产了"+i+"鸡");
            container.push(new Chicken(i));
        }


    }
}

定义消费者:

package xiong.demo6;

public class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    //消费
    @Override
    public void run() {
        int i =0;
        while(true){
            i++;
            System.out.println("消费了-->"+container.pop().id+"只鸡");
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

调用线程:

package xiong.demo6;

public class TestPC {
    public static void main(String[] args) {
        SynContainer container  = new SynContainer();

        new Productor(container).start();
        new Consumer(container).start();
    }
}

运行结果如下:

 一边生产一边消费

4 解决方式2

并发协作模型 “ 生产者 / 消费者模式 ” --->信号灯法

TV类中设置信号灯

package xiong.demo8;

public class TV {
    //演员说话 , 观众等待 true
    //观众观看 , 演员等待 false
    boolean flag = true;

    //说话
    String voice;

    //表演
    public synchronized void play(String voice){
        //演员等待
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("表演了"+voice);
        this.voice = voice;

        //让观众观看
        this.notifyAll();
        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;
    }
}

观看者类(消费者)

package xiong.demo8;

public class Watcher extends Thread {
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        while (true)
        {
            tv.watch();
        }
    }

}

表演者类(生产者)

package xiong.demo8;

public class Player extends Thread{
    TV tv;

    public Player(TV tv){
        this.tv = tv;
    }
    @Override
    public void run() {
        int i=0;
        while (true){
            i++;
            if (i%2==0){
                this.tv.play("节目:快乐大本营播放中");
            }else {
                this.tv.play("广告:抖音,记录美好生活");
            }
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e)
            {
                e.printStackTrace();
            }

        }
    }
}

测试

package xiong.demo8;

public class TestPC2 {
    public static void main(String[] args){
        TV tv = new TV();

        new Player(tv).start();
        new Watcher(tv).start();
    }
}

运行结果如下:

5 使用线程池

线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。 

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。 可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。 

好处: 

  • 提高响应速度(减少了创建新线程的时间) 
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建) 
  • 便于线程管理(....) 

        corePoolSize:核心池的大小

        maximumPoolSize:最大线程数 

        keepAliveTime:线程没有任务时最多保持多长时间后会终止

使用线程池

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

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

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

        void shutdown():关闭连接池 

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

package xiong.demo7;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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());

        //2.关闭连接
        service.shutdown();
    }
}

package xiong.demo7;

public class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chrome Extension 基础篇

Extensions are software programs, built on web technologies (such as HTML, CSS, and JavaScript) that enable users to customize the Chrome browsing experience. 扩展程序是基于 Web 技术&#xff08;例如 HTML、CSS 和 JavaScript&#xff09;构建的软件程序&#xf…

C语言递归

递归指的是在函数的定义中使用函数自身的方法。 举个例子&#xff1a; 从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚&#xff0c;正在给小和尚讲故事呢&#xff01;故事是什么呢&#xff1f;"从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚…

redis的安装

1.Redis是基于C语言编写的&#xff0c;因此首先需要安装Redis所需要的gcc依赖&#xff1a; yum install -y gcc tcl2.上传安装包并解压 tar -xzf redis-6.2.6.tar.gz3.解压后&#xff0c;进入redis目录 cd redis-6.2.64.运行编译命令 make && make install如果没有…

3_运行时数据区概述及线程

前言 本节主要讲的是运行时数据区&#xff0c;也就是下图这部分&#xff0c;它是在类加载完成后的阶段 当我们通过前面的&#xff1a;类的加载-> 验证 -> 准备 -> 解析 -> 初始化 这几个阶段完成后&#xff0c;就会用到执行引擎对我们的类进行使用&#xff0c;同时…

56. 数据增广 / 图像增广

1. CES上的真实故事 2. 数据增强 增加一个已有数据集&#xff0c;使得有更多的多样性 在语言里加入各种不同的背景噪音改变图片的颜色和形状 例如&#xff0c;我们可以以不同的方式裁剪图像&#xff0c;使感兴趣的对象出现在不同的位置&#xff0c;减少模型对于对象出现位置…

Linux系统如何添加磁盘分区基本情况

Linux系统如何添加磁盘&&分区基本情况 原理介绍 Linux来说无论有几个分区&#xff0c;分给哪一目录使用&#xff0c;它归根结底就只有一个根目录&#xff0c;一个独立且唯一的文件结构&#xff0c;Linux中每个分区都是用来组成整个文件系统的一部分。 Linux采用了一种…

JavaScript-DOM和BOM详解

文章目录DOM 和 BOM1. DOM2. BOM2.1 BOM 简介2.2 分类2.3 语法1) Navigator 当前浏览器2&#xff09;Histry 向前或向后翻页3&#xff09;Location 地址栏的信息DOM 和 BOM 1. DOM 浏览器已经为我们提供了文档节点的对象&#xff0c;这个对象是 window 对象的属性可以在页面中…

Netconf协议讲解

目录 什么是Netconf 为什么要提出Netconf 数据的类别 传统网络配置协议 Netconf配置协议 Netconf协议架构 安全传输层 消息层 操作层 内容层 Netconf配置设备流程 通过Python进行Netconf配置 什么是Netconf NETCONF&#xff08;Network Configuration Protocol&…

Unity运行时代码编辑插件介绍-InGame Code Editor-IDE类文本编辑器

因为某些原因,需要在Runtime显示一下代码,也方便做样式设计 所以找到了这个插件 特色什么的都不展开说了,开源的代码都是好代码,样式什么的就不能要求过多 基础使用方法 导入TextMeshPro 基于这个插件的,所以需要先从Package Manager先下载TextMeshPro 创建编辑器 T…

【SpringBoot应用篇】SpringBoot集成j2cache二级缓存框架

【SpringBoot应用篇】SpringBoot集成j2cache二级缓存框架j2cache介绍j2cache入门使用pomapplication.ymlcaffeine.propertiesCacheTestController启动类j2cache介绍 j2cache是OSChina(开源中国)目前正在使用的两级缓存框架。 j2cache的两级缓存结构&#xff1a; L1&#xff…

《悠悠岁月》悠悠岁月,浅藏浅忆,且行且珍惜

《悠悠岁月》悠悠岁月&#xff0c;浅藏浅忆&#xff0c;且行且珍惜 安妮埃尔诺&#xff0c;法国当代著名女作家&#xff0c;2022年获诺贝尔文学奖。埃尔诺从1974年开始创作&#xff0c;至今已出版了约十五部作品。《悠悠岁月》这部历经二十余年思考和推敲的杰作&#xff0c;使她…

Apache Shiro(一)

1.Apache Shiro Apache Shiro Reference Documentation | Apache Shiro Apache Shiro 是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完 成&#xff1a;认证、授权、加密、会话管理、与 Web 集成、缓存 等。借助 Shiro 您可以快速轻松 地保护任何应用程序——从最…

PHPExcel基本使用(2) 导入图片

一、效果二、代码一、效果 基于这篇 PHPExcel基本使用&#xff08;2&#xff09; 导入图片 调整 二、代码 基于thinkphp5.1 <?phpnamespace app\index\controller;use think\facade\Env;class Test {public function test(){self::excelAction();}/*** todo 导出报表*…

Microcontent - 微内容

这两年&#xff0c;微内容不断被人提及。微内容是什么&#xff1f;微内容解决什么问题&#xff1f;今天我们一起来看看这个话题。 作者&#xff1a;Sarah Cuellar - 1 - 什么是微内容 什么是微内容&#xff1f;微内容指的是小块的内容&#xff0c;它们遵循具体的的结构规则…

classnames 源码学习笔记与解读

前言 这里我引用源码文档中的一句话来作为开场白&#xff1a; A simple JavaScript utility for conditionally joining classNames together. 话不多说&#xff0c;咱们直接开始 classnames 的源码学习。 核心源码解读 直接来看它的源码部分&#xff0c;以下这是 classnam…

Win10的几个实用技巧系列之win10和win8系统哪个好用、系统任务栏和窗口假死的解决方法

目录 win10系统任务栏和窗口假死怎么办?win10系统任务栏和窗口假死的解决方法 win10系统任务栏和窗口假死怎么解决 Win10进不去Epic下载的死亡搁浅怎么办?Win10玩死亡搁浅闪退的解决方法 Epic领取的死亡搁浅进不去 Win10玩死亡搁浅闪退的解决方法 win10和win8系统哪个好用…

Eth09- EthCtrlConfig:以太网控制器写MAC地址到NVM中的配置

文章目录 1 MAC地址保存到非易失性存储器中传送门 ==>> AutoSAR入门和实战系列总目录 1 MAC地址保存到非易失性存储器中 如果想把MAC地址保存到非易失性存储器中,防止掉电之后MAC地址不存在了,可以通过以下的配置参数,实现实时保存MAC地址到NVM中 EthCtrlConfig/…

【Effective Objective - C】—— 读书笔记(四)

【Effective Objective - C】—— 读书笔记&#xff08;四&#xff09; 协议与分类 文章目录【Effective Objective - C】—— 读书笔记&#xff08;四&#xff09;协议与分类23.通过委托与数据源协议进行对象间通信要点&#xff1a;24.将类的实现代码分散到便于管理的数个分类…

Friedman 检验后的two-tailed Nemenyi test和the two-tailed Bonferroni-Dunn test的关键值

Critical values qαq_{\alpha}qα​ for post-hoc tests after the Friedman testCritical values qαq_{\alpha}qα​ for the two-tailed Nemenyi test Critical values qαq_{\alpha}qα​ for the two-tailed Bonferroni-Dunn test 其中classifiers是比较的方法个数&#…

【nowcoder】笔试强训Day15

目录 一、选择题 二、编程题 2.1 查找输入整数二进制中1的个数 2.2 手套 一、选择题 1.给出数据表 score(stu-id,name,math,english,Chinese), 下列语句正确的是&#xff08; &#xff09; A. Select sum(math),avg(chinese) from score B. Select *,sum(english) from …