【多线程】JUC(java.util.concurrent)的常见类 信号量 线程安全的集合类

news2025/1/10 11:50:38

目录

1. Callable接口

1.1 Callable接口和Runnable接口的区别?

1.2 使用Callable接口编写代码。

2. ReentrantLock 可重入锁

3.信号量 semaphore

3.1 Java中信号量的使用

4.CountDownLatch


JUC: java.util.concurrent ->   这个包里的内容主要是一些多线程,并发编程相关的组件。比如:

1. Callable接口

1.Callable接口,也是一种创建线程的方式。适合于想让某个线程执行一个逻辑,并且返回一个结果。相比之下,我们熟悉的Runnable(创建任务时常用)不关注结果。Callable接口使用时需要额外搭配一个FutureTask类。

1.1 Callable接口和Runnable接口的区别?

相同点:都是用来定义一个任务,从而去创建出一个线程。

不同点:

1.2 使用Callable接口编写代码。

public class vvsvvsvs {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //创建任务  使用匿名内部类的方式
        Callable<Integer> callable = new Callable<Integer>() {  //这个泛型里填的类型就是返回值的类型
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i <= 1000; i++) {
                    sum += i;
                }
                return sum;
            }
        };

        //把任务放到线程中执行
        //外创建了一个FutureTask 作用是什么?
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask);
        thread.start();
        
        //获取任务返回结果
        System.out.println(futureTask.get());

    }

}

上面代码中FutureTask的作用:在执行方法的时候,将传入的Callable对象或者Runnable对象封装成FutureTask对象,核心作用是获取有返回值的线程结果。

当FutureTask处于未启动状态时,执行futureTask.get()方法将导致调用线程阻塞。如果futureTask处于已完成状态,调用futureTask.get()方法将导致调用线程立即返回结果或者抛出异常。上面代码中调用线程指主线程。

举个例子:比如我去食堂买饭,付钱后会给我一张小票,后面要凭这张票取饭,然后后厨就相当于一个线程,就开始执行了,然后我们就要等待,等待人家做好。FutureTask对象就相当于小票,调用get方法会执行这个等待过程(阻塞等待)并在等待完成后返回结果。

2. ReentrantLock 可重入锁

ReentrantLock也是一个可重入锁,使用效果上和synchronized类似。其加锁为lock()方法,解锁为unlock()方法,其优势在于:

  1. ReentrantLock在加锁的时候有两种方式,locktryLock。其中lock当加锁没加上的时候就会进入阻塞等待,而tryLock如果加锁没加上,就直接放弃了。
  2. ReentrantLock提供了公平锁的实现方式(先到先得),默认情况下是非公平锁。
  3. ReentrantLock提供了更强大的等待通知机制,搭配了Condition类,来实现等待通知。

用法:

import java.util.concurrent.locks.ReentrantLock;

public class test {
    public static void main(String[] args) {
        
        ReentrantLock lock = new ReentrantLock();
        lock.lock();  //加锁
        try{
            //.....
        }finally{
            lock.unlock();  //解锁 一定要注意解锁 容易忘记
        }
    }

}

虽然ReentrantLock优势挺多,但是同时ReentrantLock的使用也更加复杂,尤其是容易忘记解锁。所以在加锁的时候,还是首选synchronized。

两个可重入锁的区别?

3.信号量 semaphore

信号量:操作系统中比较重要的概念。用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作。

信号量其实就是一个变量,也可理解为是一个计数器,它描述了系统"可用资源"的个数,即某一种系统可用资源的剩余个数,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。

操作:

  • 每次申请一个可用资源,就需要让这个变量(计数器) - 1,称为P操作。
  • 每次释放一个可用资源,就需要让这个变量(计数器) + 1,称为V操作。 

这里的+1,-1操作都是原子的。对信号量的操作基本有三种,即初始化,P操作,V操作。提出信号量的大佬是迪杰斯特拉。

假设初始条件下,某一个信号量是2,每次进行P操作,就会-1,进行2次操作后,信号量就是0了,此时如果我还继续进行P操作,就会进行阻塞等待。

这里的阻塞等待和我们学过的锁有点相似。其实锁本质上就是属于一种特殊的信号量。我们给锁初始化可用资源数为1,那么加锁操作就会-1,减到0后无可用资源了,就会阻塞等待,直到解锁(释放锁)操作执行就会+1,属于是一种二元信号量。

3.1 Java中信号量的使用

Java中对应的P操作是acquire()方法,V操作是reserve()方法。开发中如果用到了需要申请资源的场景,就可以使用信号量来实现了。

public class test {
    public static void main(String[] args) throws InterruptedException {

        Semaphore semaphore = new Semaphore(4); // 4为初始化信号量个数
        semaphore.acquire();  // P操作
        System.out.println("P操作3");
        semaphore.acquire();
        System.out.println("P操作2");
        semaphore.acquire();
        System.out.println("P操作1");
        semaphore.acquire();
        System.out.println("P操作0");

//由于初始化信号量为4,上面已经连续4次P操作,信号量为0,下面这次P操作会进入阻塞等待
        semaphore.acquire(); 
        
    }

}

4.CountDownLatch

这个东西主要是适用于多个线程来完成一系列任务的时候,用来衡量任务的进度是否完成。比如需要把一个任务拆分成多个小的任务,让这些小的任务并发的去执行(多线程)。就可以使用CountDownLatch来判定当前这些小任务是否都完成了。适合于将一个大任务拆分成多个小任务的场景下。

举个例子:当我们要下载一个文件,使用某些工具没充会员时下载速度会很慢,但是当你充会员后下载,速度会成倍的提升。极有可能是没充会员时线程和资源服务器之间只有一个连接,这样传输速度就会受到限制。而充了会员后为何就能下载如此之快,它把下载文件这个大任务,分割成多个小任务,再使用多线程进行下载。

使用CountDownLatch的两个主要方法 await 和 countDown

await方法:调用的时候就会阻塞,就会等待其他线程完成任务,所有的线程都完成了任务之后,此时这个await才会返回,并继续往下执行。

countDown方法: 告诉countDownLatch,我当前这一个子任务已经完成了。

CountDownLatch在初始化时,需要指定一个整数作为计数器。当调用countDown方法时,计数器会被减1,;当调用await方法时,如果计数器大于0时,线程会被阻塞,一直阻塞到计数器被countDown方法减到0时,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用await方法都会直接返回,继续向下执行。

public static void main(String[] args) throws InterruptedException {
        CountDownLatch count = new CountDownLatch(10); //初始化10个
        for(int i=0;i<10;i++) {
            int id = i;
            Thread thread = new Thread(() -> {
                System.out.println("Thread"+id);
                count.countDown();//调用一下,一个子线程完成 并且初始化数-1
            });

            thread.start();
        }

        count.await(); // 数字大于0时,调用await会阻塞等待 直到初始化数--为0时,继续往下执行
        System.out.println("所有线程都执行完了!");
    }

注意:如果我初始化值设为10,但才调用了countDown方法不到10次,线程就会一直等待阻塞下去。如果不想一直等待下去,可以使用另一个带参的await方法。

count.await(3,TimeUnit.SECONDS); //参数为 数字 + 单位

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

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

相关文章

智能变电站自动化系统的应用与产品选型

摘要&#xff1a;现如今&#xff0c;智能变电站发展已经成为了电力系统发展过程中的内容&#xff0c;如何提高智能变电站的运行效率也成为电力系统发展的一个重要目标&#xff0c;为了能够更好地促进电力系统安全稳定运行&#xff0c;本文则就智能变电站自动化系统的实现进行了…

青藏高原连续日光诱导叶绿素荧光数据集(2000-2018)

简介&#xff1a; 青藏高原连续日光诱导叶绿素荧光数据集&#xff08;2000-2018&#xff09;是通过MODIS各通道反射率和SIF观测数据建立神经网络模型&#xff0c;从而得到较高时空分辨率的SIF数据&#xff0c;常作为初级生产力的参考。前言 – 人工智能教程 源数据范围为全球&…

网工实验笔记:MQC原理与配置

一、概述 MQC&#xff08;Modular QoS Command-Line Interface&#xff0c;模块化QoS命令行&#xff09;是指通过将具有某类共同特征的数据流划分为一类&#xff0c;并为同一类数据流提供相同的服务&#xff0c;也可以对不同类的数据流提供不同的服务。 MQC三要素 流分类&am…

15-k8s-高级存储之pv与pvc

文章目录 一、相关概念二、创建pv二、创建pvc三、创建pod调用pvc四、StorageClass动态制备pv 一、相关概念 关系 生命周期相关概念 2.1 静态构建&#xff1a;集群管理员创建若干PV卷。这些卷对象带有真实存储的细节信息,并且对集群用户可用(可见)。PV卷对象存在于Kubernetes …

摩尔信使MThings的设备高级参数

摩尔信使MThings支持三级参数管理方案&#xff0c;依次为&#xff1a;数据级、设备级、通道级。 设备级参数不仅包含设备名称、设备地址等常用信息&#xff0c;同时提供了诸多高级参数&#xff0c;其同样是为了满足不同用户应用场景中所面临的差异化需求&#xff0c;以更加灵活…

勒索病毒LockBit2.0 数据库(mysql与sqlsever)解锁恢复思路分享

0.前言 今天公司服务器中招LockBit2.0勒索病毒&#xff0c;损失惨重&#xff0c;全体加班了一天基本解决了部分问题&#xff0c;首先是丢失的文件数据就没法恢复了&#xff0c;这一块没有理睬&#xff0c;主要恢复的是两个数据库&#xff0c;一个是16GB大小的SQLserver数据库&…

安徽阳光心理测量平台目录遍历

安徽阳光心理测量平台目录遍历 FOFA指纹 title"心理测量平台"漏洞复现 路由后拼接/admin/UserFiles/ GET /admin/UserFiles/ HTTP/1.1 Host: {{Hostname}}修复方案 针对路径设定对应权限

注释的重要性与程序员的责任

注释的重要性与程序员的责任 提升代码可读性促进团队协作提高代码可维护性传承知识和经验代码的责任推荐学习 导语&#xff1a;在编写代码的过程中&#xff0c;注释是程序员们经常讨论的话题。有人认为忽视注释等于耍流氓&#xff0c;但也有人觉得注释只是浪费时间。本文将探讨…

软件开发项目文档系列之三如何撰写项目招标文件

前言 招标文件在采购过程中扮演着至关重要的角色&#xff0c;其主要目的是提供清晰而详尽的信息&#xff0c;以确保采购项目的需求得以明确&#xff0c;潜在的投标单位能够清晰理解并遵守相关要求&#xff0c;并最终为采购方提供一个有力的依据来评估和选择最合适的承建单位。…

c++之new和delete

前言 在本文中&#xff0c;您将学习使用new和delete操作在C 中有效地管理内存。 数组可用于存储多个同类型数据&#xff0c;但是使用数组存在严重的缺点。声明数组时应分配内存&#xff0c;但在大多数情况下&#xff0c;直到运行时才能确定所需的确切内存。在这种情况下&#…

python每日一练(8)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

微信小程序开发指南

前言 微信是一款由中国著名互联网公司腾讯公司开发的社交软件&#xff0c;于2011年1月21日正式上线。在成立后的短短几年时间里&#xff0c;微信以其简单易用的界面和强大的功能&#xff0c;快速赢得了全球用户的青睐。截止2021年&#xff0c;微信已经有超过10亿的活跃用户&am…

如何使用 OpenSSL 来检查证书,来确保网络通信的安全性?

OpenSSL 是一个强大的安全套接字层密码库&#xff0c;包含丰富的加密算法、常用的密钥和证书封装管理功能以及 SSL/TLS 协议&#xff0c;并提供了丰富的应用程序供测试或其他目的使用。要使用 OpenSSL 来检查证书以确保网络通信的安全性&#xff0c;您可以遵循以下步骤&#xf…

【ARM Coresight Debug 系列 16 -- Linux 断点 BRK 中断使用详细介绍】

文章目录 1.1 ARM BRK 指令1.2 BRK 立即数宏定义介绍1.3 断点异常处理流程1.3.1 el1_sync_handler1.3.2 el1_dbg 跟踪 1.4 debug 异常处理函数注册1.4.1 brk 处理函数的注册 1.1 ARM BRK 指令 ARMv8 架构的 BRK 指令是用于生成一个软件断点的。当处理器执行到 BRK 指令时&…

【小黑嵌入式系统第二课】嵌入式系统的概述(二)

文章目录 一、嵌入式系统的组成二、嵌入式处理器三、嵌入式外围设备1. 存储设备2. 通信设备3. 显示设备 四、硬件抽象层HAL五、嵌入式操作系统六、应用程序七、嵌入式处理器1、MCU2、MPU3、DSP4、SOC5、SOPC 八、ARM处理器简介ARM处理器的特点ARM处理器的发展历程ARM体系结构版…

【递归知识+练习】

文章目录 递归♥♥♥ 栈存储的顺序&#xff1a;按顺序打印一个数字的每一位递归求N&#xff01;的阶层递归求1234...10写一个递归方法&#xff0c;输入一个非负整数。返回组成它的数字之和&#xff08;不熟&#xff09;斐波那契数列&#xff08;不熟&#xff09; 总结 递归 递…

【(数据结构)— 单链表的实现】

&#xff08;数据结构&#xff09;— 单链表的实现 一.链表的概念及结构二.单链表的实现2.1单链表头文件——功能函数的定义2.2单链表源文件——功能函数的实现2.3 单链表源文件——功能的测试2.4单链表测试结果运行展示 3. 链表的分类 一.链表的概念及结构 概念&#xff1a; …

电子学会2023年9月青少年软件编程(图形化)等级考试试卷(三级)真题,含答案解析

青少年软件编程(图形化)等级考试试卷(三级) 分数:100 题数:31 一、单选题(共18题,共50分) 1.运行下面程序后,角色的x坐标值是?( ) A. 100 B. 90

osWorkflow-1——osWorkflow官方例子部署启动运行(版本:OSWorkflow-2.8.0)

osWorkflow-1——osWorkflow官方例子部署启动运行&#xff08;版本&#xff1a;OSWorkflow-2.8.0&#xff09; 1. 前言——准备工作1.1 下载相关资料1.2 安装翻译插件 2. 开始搞项目2.1 解压 .zip文件2.2 简单小测&#xff08;war包放入tomcat&#xff09;2.3 导入项目到 IDE、…

137.【SpringCloud-快速搭建】

微服务框架搭建 (一)、SpringCloud-Parent1.创建一个SpringBoot项目2.导入我们的依赖 (二)、SpringCloud-API (实体类)1.创建一个SpringBoot项目2.导入我们的依赖3.创建我们的实体类 (三)、SpringCloud-dept (业务A)1.创建一个SpringBoot项目2.导入我们的依赖3.配置我们的配置信…