Java并发编程实战读书笔记二

news2025/8/12 8:07:48

第五章 基础构建模块

5.1 同步容器类

5.1.1 同步容器类的问题

如下,如果list含有10个元素,线程A调用getLast的同时线程B调用deleteLast,那么getLast可能会报ArrayIndexOutOfBoundsException

 改为如下方式能确保size和get一致

Vector迭代也可能引发异常

 

改进后的方式安全了,但降低了并发性

5.1.3 隐藏迭代器

如下可能抛出ConcurrentModificationException,以内printn ……+set 这步操作会对set进行迭代,那么在并发调用addTenThings情况下,可能出现线程A迭代set,线程B修改set的情况,所以报出ConcurrentModificationException

 

5.2.1 ConcurrentHashMap

采用分段锁、吞吐性能更高

5.4 阻塞方法与中断方法

当A线程发送中断信号给到B线程,B线程可以选择向上层传递或者在catch块恢复中断状态(catch后中断状态会被重置回原来的状态),让上层代码能看到这个状态

 5.5 同步工具类

同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。阻塞队列可以作为同步工具类,其他类型的同步工具类还包括信号量 (Semaphore)、栅栏(Barrier)以及闭锁 (Latch)。

5.5.1 闭锁

CountDownLatch

CountDownLatch用法,测试N个线程并发执行某个任务时需要的时间。

public class TestHarness {

    public static void main(String[] args) throws InterruptedException {
            timeTasks(10,null);
    }

    public static long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
        final CountDownLatch startGate = new CountDownLatch(1);
        final CountDownLatch endGate = new CountDownLatch(nThreads);
        for (int i = 0;i<nThreads;i++){
            Thread t = new Thread(() -> {
                try {
                    startGate.await();
                    try {
                        //task.run();
                        System.out.println("countDown测试");
                    } finally {
                        endGate.countDown();
                    }
                } catch (InterruptedException e) {
                    //throw new RuntimeException(e);
                }
            });
            t.start();
        }
        long start = System.nanoTime() ;
        System.out.println("start:"+start);
        startGate.countDown();
        endGate.await();
        long end = System.nanoTime ();
        System.out.println("end:"+end);
        return end-start;
    }
}

 5.5.2 FutureTask也可用作闭锁

通过Callable实现,相当于一种可生成结果的Runnable。FutureTask没完成的话get()方法会阻塞

public class Preloader {

    public static void main(String[] args) throws InterruptedException{
        Preloader preloader=new Preloader();
        preloader.start();
        System.out.println("调用get方法");
        preloader.get();
    }
    private final FutureTask<ProductInfo> future =
            new FutureTask(new Callable<ProductInfo>() {
                public ProductInfo call() {
                    return loadProductInfo();
                }
            });
    private final Thread thread = new Thread(future);

    public void start() {
        thread.start();
    }

    public ProductInfo get() throws InterruptedException {
        try {
            ProductInfo productInfo = future.get();
            System.out.println("得到future返回:"+productInfo);
            return productInfo;
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            return null;
        }
    }
    public ProductInfo loadProductInfo () {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
}

class ProductInfo {

}

Callable表示的任务可以抛出异常或者Error,这些异常都会被封装为 ExecutionException,作为Throwable类返回

public class Preloader {

    public static void main(String[] args) throws InterruptedException{
        Preloader preloader=new Preloader();
        preloader.start();
        System.out.println("调用get方法");
        preloader.get();
    }
    private final FutureTask<ProductInfo> future =
            new FutureTask(new Callable<ProductInfo>() {
                public ProductInfo call() throws NumberFormatException{
                    return loadProductInfo();
                }
            });
    private final Thread thread = new Thread(future);

    public void start() {
        thread.start();
    }

    public ProductInfo get() throws InterruptedException {
        try {
            ProductInfo productInfo = future.get();
            System.out.println("得到future返回:"+productInfo);
            return productInfo;
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            System.out.println("获取异常");
            e.printStackTrace();
            return null;
        }
    }
    public ProductInfo loadProductInfo () throws NumberFormatException{
        try {
            Integer.valueOf("a");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
}

class ProductInfo {

}

5.5.3 信号量Semaphore

用于控制同时访问某个特定资源的操作数量、互斥锁、连接池、将容器变成有界阻塞容器

 5.5.4 栅栏CyclicBarrier

转载自:CyclicBarrier 使用详解 - 简书

1. CyclicBarrier 是什么?

从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。

它的作用就是会让所有线程都等待完成后才会继续下一步行动。

举个例子,就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。

2. 怎么使用 CyclicBarrier

2.1 构造方法

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)

解析:

  • parties 是参与线程的个数
  • 第二个构造方法有一个 Runnable 参数,这个参数的意思是最后一个到达线程要做的任务

2.3 基本使用

2.3.1 需求

一个线程组的线程需要等待所有线程完成任务后再继续执行下一次任务

2.3.2 代码实现

public class CyclicBarrierDemo {

    static class TaskThread extends Thread {
        
        CyclicBarrier barrier;
        
        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(getName() + " 到达栅栏 A");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 A");
                
                Thread.sleep(2000);
                System.out.println(getName() + " 到达栅栏 B");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 B");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        int threadNum = 5;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
            
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务");
            }
        });
        
        for(int i = 0; i < threadNum; i++) {
            new TaskThread(barrier).start();
        }
    }
    
}

 打印结果:

Thread-1 到达栅栏 A
Thread-3 到达栅栏 A
Thread-0 到达栅栏 A
Thread-4 到达栅栏 A
Thread-2 到达栅栏 A
Thread-2 完成最后任务
Thread-2 冲破栅栏 A
Thread-1 冲破栅栏 A
Thread-3 冲破栅栏 A
Thread-4 冲破栅栏 A
Thread-0 冲破栅栏 A
Thread-4 到达栅栏 B
Thread-0 到达栅栏 B
Thread-3 到达栅栏 B
Thread-2 到达栅栏 B
Thread-1 到达栅栏 B
Thread-1 完成最后任务
Thread-1 冲破栅栏 B
Thread-0 冲破栅栏 B
Thread-4 冲破栅栏 B
Thread-2 冲破栅栏 B
Thread-3 冲破栅栏 B

从打印结果可以看出,所有线程会等待全部线程到达栅栏之后才会继续执行,并且最后到达的线程会完成 Runnable 的任务。

3. CyclicBarrier 使用场景

可以用于多线程计算数据,最后合并计算结果的场景。

4. CyclicBarrier 与 CountDownLatch 区别

  • CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
  • CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。

5.6 构建高效且可伸缩的结果缓存

第六章 任务执行

6.1 在线程中执行任务

6.2.3 线程池

在线程池中执行任务比“为每个任务分配一个线程”优势更多。通过重用现有的线程而不是创建新线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销。另一个额外的好处是,当请求到达时,工作线程通常已经存在,因此不会由于等待创建线程而延迟任务执行,提高了响应性。通过适当调整线程池的大小,可以创建足够多的线程以便使处理器保持忙碌状态,同时还可以防止过多线程相互竞争资源而使应用程序耗尽内存或失败

newFixedThreadPool。newFixedThreadPool将创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化(如果某个线程由于发生了未预期的 Exception 而结束,那么线程池会补充一个新的线程)。

newCachedThreadPool。newCachedThreadPool将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线
程,线程池的规模不存在任何限制。

newSingleThreadExecutor。newSingleThreadExecutor是一个单线程的 Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来替代。newSingleThreadExecutor能确保依照任务在队列中的顺序来串行执行(例如 FIFO、LIFO优先级)。

newScheduledThreadPool。newScheduledThreadPool 创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于 Timer

newWorkStealingPool://todo

6.2.4 Executor的生命周期

JVM 只有在所有(非守护)线程全部终止后才会退出。因此,如果无法正确地关闭 Executor,那么JVM 将无法结束。

6.3.2 携带结果的任务 Callable 与 Future

要使用 Callable 来表示无返回值的任务,可使用 Callable<Void>

Executor 执行的任务有 4 个生命周期阶段:创建、提交、开始和完成

get 方法的行为取决于任务的状态(尚未开始、正在运行、已完成)。如果任务已经完成,那么 get 会立即返回或者抛出一个 Exception,如果任务没有完成,那么get 将阻塞并直到任务完成。如果任务抛出了异常,那么 get 将该异常封装为 ExecutionException 并重新抛出。如果任务被取消,那么get 将抛出 CancellationException。如果 get 抛出了 ExecutionException,那么可以通过 getCause 来获得被封装的初始异常。

future.cancle(true) 取消任务

使用future等待图像下载

 6.3.5 CompletionService;Executor 与 BlockingQueue

采用CompletionService实现边下载图片边加载图片的功能(下载好一个图片就加载一个图片),内部实现采用了队列

 6.3.7为任务设置时限

线程任务执行超时直接取消,通过future.get()设置超时时间

 使用invokeAll提交一组任务,返回一组结果List<Future>

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

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

相关文章

【795. 区间子数组个数】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个整数数组 nums 和两个整数&#xff1a;left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组&#xff0c;并返回满足条件的子数组的个数。 生成的测试用例…

微信小程序| 用小程序复刻微信Wechat

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;小程序开发成神之路 --【这是一个为想要入门和进阶小程序开发专门开启的精品专栏&#xff01;从个人到商业的全套开发教程&#xff0c;实打实的干货分享&#xff0c;确定不来看看&#xff1f; …

新的趋势:From Big to Small and Wide data

新的趋势&#xff1a;From Big to Small and Wide data 所以&#xff0c;在这个时候&#xff0c;作为率先提出要做 MySQL 开源 HTAP 数据库的 StoneDB&#xff0c;想要稍微冷静一下。 不是说我们不做 HTAP 了&#xff0c;而是有了一个新的思路。这个思路&#xff0c;也同样来…

【模型训练】YOLOv7车辆三类别检测

YOLOv7车辆三类别检测 1、车辆三类别检测模型训练2、模型评估3、模型和数据集下载网盘链接1、本项目采用YOLOv7算法实现对车辆三类别检测,在几千多张车辆三类别数据集中训练得到,我们训练了YOLOv7、,所有指标都是在同一个验证集上得到; 2、目标类别数:3;类别名:car、bus…

【蓝桥杯选拔赛真题29】python堆砖块 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python堆砖块 一、题目要求 1、提示信息 1、编程实现 2、输入输出

WindowsServer域控的安装与卸载

搭建域服务器 1.安装域控 打开服务器管理器, 点击右上角的管理, 选择添加角色和功能 一直点击下一步,直到选择服务器角色处, 勾选Active Directory域服务器 一直下一步&#xff0c;然后点击安装 安装完毕后将此服务器提升为域控制器 自行设置DSRM的密码, 后面一直点击下一步直…

【优化调度】遗传算法求解公交车调度排班优化问题【含Matlab源码 2212期】

⛄ 一、 遗传算法简介 1 引言 公交排班问题是城市公交调度的核心内容,是公交调度人员、司乘人员进行工作以及公交车辆正常运行的基本依据。行车时刻表是按照线路的当前客流量情况,确定发车频率,提供线路车辆的首、末车时间。它是公交企业对社会的承诺,决定着为乘客服务的水平,…

2023-2028年中国花炮行业市场供需与投资预测分析报告

本报告由锐观咨询重磅推出&#xff0c;对中国花炮行业的发展现状、竞争格局及市场供需形势进行了具体分析&#xff0c;并从行业的政策环境、经济环境、社会环境及技术环境等方面分析行业面临的机遇及挑战。还重点分析了重点企业的经营现状及发展格局&#xff0c;并对未来几年行…

【Java 设计模式】简单工厂模式 静态工厂模式

简单工厂模式 & 静态工厂模式1 简单工厂模式1.1 角色1.2 点咖啡案例1.2.1 类图1.2.2 实现1.3 优点1.4 缺点2 静态工厂模式2.1 代码变动2.2 优点1 简单工厂模式 简单工厂模式并不属于 23 种设计模式。 1.1 角色 抽象产品&#xff1a;定义产品的规范&#xff0c;描述产品的…

相控阵天线(七):常规平面阵列分布(矩形阵列、三角栅格、六边形阵列和圆形阵列)

目录简介矩形栅格平面阵列三角栅格平面阵列六边形阵列圆形平面阵列空心平面阵列简介 常见的平面阵有一些基本类型&#xff0c;按照栅格形式可以进行以下划分&#xff1a;矩形栅格、三角形栅格、同心圆环和椭圆环栅格等&#xff1b;按照边界形式可以进行以下划分&#xff1a;矩…

React Native Webview 中input type=file accept=“image/*“ 无法调起相机问题排查及解决

最近在写一个react native 项目&#xff0c;其中react-native-webview库一些使用着实遇到了不少问题&#xff0c;耗时比较长&#xff0c;现在和大家分享一下。 图片上传时选择拍照是很常见的功能&#xff0c;写的h5项目一直调用正常。使用方式大概如下&#xff1a; <input…

【数据结构】—— 双链表的增删改查

❤️一名热爱Java的大一学生&#xff0c;希望与各位大佬共同学习进步❤️ &#x1f9d1;个人主页&#xff1a;周小末天天开心 各位大佬的点赞&#x1f44d; 收藏⭐ 关注✅&#xff0c;是本人学习的最大动力 感谢&#xff01; &#x1f4d5;该篇文章收录专栏—数据结构 目录 双…

艾美捷小鼠肿瘤坏死因子α-ELISpot试剂盒使用指南

ELISpot Plus for enumeration of cells secreting TNF-α This kit is ideal for users who want a convenient and sensitive assay. The assay is designed for the enumeration of cells secreting mouse TNF-α. The kit includes ELISpot plates pre-coated with monocl…

[附源码]计算机毕业设计JAVA面试刷题系统

[附源码]计算机毕业设计JAVA面试刷题系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis M…

【C++】--模拟实现vector

文章目录Constructors(构造函数)myvector()myvector(int n, const T& val T())myvector(InputIterator first, InputIterator last)拷贝构造交换函数myvector< T >& operator(myvector< T > v)迭代器扩容reserveresize插入和删除push_backpop_backinserte…

CDH启用kerberos 高可用运维实战

一、背景说明 在前的文章中介绍过《CDH集成的kerberos迁移实战》,由此也考虑到kerberos单节点可能引发的线上事故&#xff0c;所有考虑到把线上kerberos服务启用高可用。 二、环境介绍 系统版本 CentOS Linux release 7.6.1810 (Core) CM版本 Kerberos版本 三、实操…

桌面应用开发有哪些主流框架?

受益于开源技术的发展&#xff0c;以及响应快速开发的实际业务需求&#xff0c;跨平台开发不仅限于移动端跨平台&#xff0c;桌面端虽然在市场应用方面场景不像移动端那么丰富&#xff0c;但也有市场的需求。 相对于个人开发者而言&#xff0c;跨平台框架的使用&#xff0c;主要…

零基础学习下载FL Studio2023水果编曲软件

FL Studio工具常称水果编曲软件&#xff0c;是一款功能强大的编曲软件&#xff0c;集编曲&#xff0c;录音&#xff0c;剪辑&#xff0c;混音于一身&#xff0c;简单易上手&#xff0c;灵活性高&#xff0c;强大到突破想象。FL Studio&#xff0c;当前版本 FL Studio21&#xf…

Transductive Learning 和 Inductive Learning

简介 在 kipf-GCN 和 GraphSage 中&#xff0c;对 Transductive Learning 和 Inductive Learning 有了比较深刻的认识。 kipf-GCN 在其论文中提到算法属于 transductive node classification&#xff0c;也就是在训练节点embedding的时候要看到全图的节点&#xff0c;这是因为…

Linux——进程间通信(共享内存)

一、共享内存 1、定义 共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间&#xff0c;多个进程可以将其映射到自己的虚拟地址空间中。所有进程都可以访问共享内存中的地址&#xff0c;就好像它们是由malloc分配的一样。如果某…