JUC的常见类

目录

Callable

ReentrantLock

Semaphore

CountDownLatch


JUC java.util.concurrent,其中存放了一些进行多线程编程时有用的类

Callable

Callable是一个接口,在我们实现Runnable创建线程时,Runnable关注的是其过程,而不关注其执行结果(其返回值为void),而Callable会关注执行结果,Callable提供了call方法,其返回值就是线程执行任务得到的结果

因此,当我们在编写多线程代码时,希望得到线程种代码的返回值时,就可以使用Callable

例如:一个线程需要实现 1 + 2 + 3 + ... + 100,并返回其结果

若我们使用实现Runnable的方式创建线程时:

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                int ret = 0;
                for (int i = 1; i <= 100; i++) {
                    ret += i;
                }
            }
        });
        t.start();
        t.join();
    }
}

若此时主线程需要获取到其计算结果,则需要使用一个成员变量来保存结果

public class Demo1 {
    private static int sum = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                int ret = 0;
                for (int i = 1; i <= 100; i++) {
                    ret += i;
                }
                sum = ret;//保存结果
            }
        });
        t.start();
        t.join();
        System.out.println(sum);
    }
}

而若我们使用Callable时:

Callable<V> 其中泛型参数表示返回值的类型
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int ret = 0;
                for (int i = 1; i <= 100; i++) {
                    ret += i;
                }
                return ret;
            }
        };

此时就不必引入额外的成员变量了,直接使用返回值即可

然而,Thread未提供构造函数来传入callable

此时,我们需要使用 FutureTask 来作为Thread和callable的“粘合剂”

将callable实例使用FutureTask包装一下,再在构造方法传入FutureTask:

此时线程就会执行FutureTask内部的Callable中的call方法,计算完成后,就将结果放入FutureTask对象中

FutureTask<V> 泛型参数表示结果的类型

此时在主线程中调用FutureTask中的get()方法(带有阻塞功能),等待计算完毕,从FutureTask中获取到结果

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int ret = 0;
                for (int i = 1; i <= 100; i++) {
                    ret += i;
                }
                return ret;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();

        //此时无需使用join,使用futureTask中的get()方法获取到结果
        System.out.println(futureTask.get());
    }
}

观察两种实现方式,我们可以发现:

使用Callable和FutureTask,使代码简化了很多,且不用使用成员变量来保存结果

Callable和Runnable相对,都是描述一个“任务”,Callable描述的是带有返回值的任务,Runnable描述的是不带返回值的任务

Callable通常需要搭配FutureTask使用,FutureTask用来保存Callable的返回结果

ReentrantLock

ReentrantLock是一种可重入互斥锁,与synchronized类似,都是用来实现互斥效果,保证线程安全的

ReentrantLock的用法:

lock():加锁,若获取不到锁就死等

unlock():解锁

tryLock(超时时间):加锁,若获取不到锁,等待时间一定后就放弃加锁

当我们在使用ReentrantLock时,需要加锁和解锁两个操作,因此当我们在加锁后,很容易忘记解锁,例如在unlock之前,触发了异常 或 return语句,此时就可能不会执行unlock

因此,为了保证unlock的执行,我们可以将其放在finally中

例如:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try{
    //执行代码
}finally {
    lock.unlock();
}

synchronzied使用时无需手动释放锁,ReentrantLock使用时需要手动释放,使用起来更加灵活,但也容易漏掉unlock 

为什么有了synchronized后,还有ReentrantLock?


1. ReentrantLock提供了tryLock操作。lock直接进行加锁,当加锁失败时,就阻塞,而tryLock尝试进行加锁,若加锁失败,等待一定时间后,不阻塞,直接放弃加锁,返回 false,表示加锁失败

2. ReentrantLock提供了公平锁的实现(遵循“先来后到”规则,即等待时间长的线程先获取到锁)。通过队列来记录加锁线程的先后顺序,ReentrantLock默认是非公平锁,在构造方法中传入true 则可设置为公平锁

3. 更强大的唤醒机制。synchronized,搭配wait和notify来实现等待唤醒,每次随机唤醒一个等待的线程;而ReentrantLock,搭配Condition类来实现通知等待机制,可以更精确控制唤醒某个指定的线程

Semaphore

信号量Semaphore,用来表示“可用资源的个数”,其本质就是一个计数器

当申请资源时,可用资源数 -1(信号的P操作)

 当释放资源时,可用资源数 +1(信号的V操作)

Semaphore中的加减计算操作都是原子的,可以在多线程环境下直接使用

信号量也是操作系统提供的机制,JVM对其对应的API进行封装,因此我们可用直接通过Java代码来调用这里的相关操作

Semaphore类中acquire()方法表示申请资源(P操作),release()方法表示释放资源(V操作)

例如:

public class Demo2 {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5);//有5个可用资源

        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        System.out.println("申请资源");
                        semaphore.acquire();
                        System.out.println("获取到资源");
                        Thread.sleep(1000);
                        System.out.println("释放资源");
                        semaphore.release();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}

CountDownLatch

同时等待多个任务执行结束

例如,构造CountDownLatch实例latch,初始化n表示有n个任务需要完成。

在任务执行完毕时,调用countDown()方法,告知latch当前任务执行完毕,则CountDownLatch内部的计数器 -1

在主线程中调用latch.await(),阻塞等待所有任务都执行完毕(计数器为0)

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class Demo3 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(10);//此时有10个任务需要完成
        for (int i = 0; i < 10; i++) {
            int id = i;
            Thread t = new Thread(()->{
                Random random = new Random();
                int time = (random.nextInt(5) + 1) * 1000;//执行任务的时间
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(id + "任务执行结束");
                //告知latch执行结束
                latch.countDown();
            });
            t.start();
        }
        //通过await来等待所有任务执行结束
        latch.await();
        System.out.println("所有任务都已执行完成");
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【1】SM4 CBC-MAC 机制

0x01 题目 MSG1: e55e3e24a3ae7797808fdca05a16ac15eb5fa2e6185c23a814a35ba32b4637c2 MAC1: 0712c867aa6ec7c1bb2b66312367b2c8 ----------------------------------------------------- MSG2: d8d94f33797e1f41cab9217793b2d0f02b93d46c2ead104dce4bfec453767719 MAC2: 4366…

【CF闯关练习】—— 1400分(C. Make Good、B. Applejack and Storages)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;cf闯关练习 &#x1f48c;其他专栏&#xff1a; &#x1f534;每日一题 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓…

016-Vue-黑马2023:前后端分离开发(在线接口文档),前端工程化、Element、nginx

第三节 前后端分离开发 1、介绍 开发模式 前后端混合开发&#xff1a;传统开发模式 前后端分离开发&#xff1a;当前最为主流的开发模式 页面原型需求案例&#xff1a;分析出接口文档 离线开发文档示例&#xff1a; 2、YAPI&#xff08;官网已停用&#xff09; 202…

【工作记录】基于springboot3+springsecurity6实现多种登录方式(一)

前言 springboot3已经推出有一段时间了&#xff0c;近期公司里面的小项目使用的都是springboot3版本的&#xff0c;安全框架还是以springsecurity为主&#xff0c;毕竟亲生的。 本文针对基于springboot3和springsecurity实现用户登录认证访问以及异常处理做个记录总结&#x…

NVMe-oF RDMA vs. TCP延时测试对比:端到端SPDK的意义

前不久看到一篇《NVIDIA BlueField 再创 DPU 性能世界纪录》的新闻&#xff0c;该测试环境是2台服务器&#xff0c;每台各安装2块NVIDIA Bluefield-2 DPU&#xff0c;形成4条100GbE以太网直连&#xff0c;两端分别跑NVMe-oF Target&#xff08;存储目标&#xff09;和Initiator…

Spring IoC 和 DI

文章目录 1. 什么是 Spring2. 什么是 IoC3. 什么是 DI4. IoC & DI 使用5. 获取 Bean 的方式5.1 根据类型获取 bean5.2 根据名称获取 bean5.3 获取bean对象的其他方式5.4 五大注解的关联 6. 方法注解7. 扫描路径8. Bean 的名称9. DI 详解9.1 属性注入9.2 构造方法注入9.3 Se…

残差网络 ResNet

目录 1.1 ResNet 2.代码实现 1.1 ResNet 如上图函数的大小代表函数的复杂程度&#xff0c;星星代表最优解&#xff0c;可见加了更多层之后的预测比小模型的预测离真实最优解更远了&#xff0c; ResNet做的事情就是使得模型加深一定会使效果变好而不是变差。 2.代码实现 impo…

【OpenAI】自定义GPTs应用(GPT助手应用)及外部API接口请求

11月10日&#xff0c;OpenAI正式宣布向所有ChatGPT Plus用户开放GPTs功能 简而言之&#xff1a;GPT应用市场(简称GPTs, 全称GPT Store) Ps&#xff1a; 上图为首次进入时的页面&#xff0c;第一部分是自己创建的GPTs应用&#xff0c;下面是公开可以使用的GPTs应用 一、创建GPTs…

Spring Cloud 微服务中 gateway 网关如何设置健康检测端点

主要是为了让 k8s 识别到网关项目已经就绪&#xff0c;但是又不想在里面通过 Controller 实现。因为在 Controller 中这样做并不是最佳实践&#xff0c;因为 Gateway 的设计初衷是专注于路由和过滤&#xff0c;而不是业务逻辑的处理。 在 Gateway 中配置健康检查端点可以通过以…

单向不带头链表的使用

单向不带头链表的使用 链表的创建&#xff1a; typedef struct LNode {SLDataType data;struct LNode* next; }LNode,*LinkList; 按位查找 LNode* GetElem(LinkList L, int i) {int j 1;LNode* p L->next;if (i < 0)return NULL;if (i 0)return L;while (p &&…

4种方法用Python批量实现多Excel多Sheet合并

目录 方法一&#xff1a;使用pandas库 方法二&#xff1a;使用openpyxl库 方法三&#xff1a;使用xlrd和xlwt库 方法四&#xff1a;使用os和glob库 在数据处理中&#xff0c;经常需要将多个Excel文件中的多个工作表进行合并。以下介绍了4种方法&#xff0c;使用Python批量实…

消费增值模式:引领消费者与平台共创双赢的新篇章

在数字化时代&#xff0c;消费模式正在发生深刻变革。消费者不再满足于单纯的购物行为&#xff0c;而是寻求更加个性化和有价值的消费体验。而平台也面临着如何吸引和留住消费者的挑战。消费增值模式作为一种新型的商业模式&#xff0c;正逐渐成为解决这一问题的关键。 消费增…

Java多线程并发篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、寄存器二、程序计数器三、PCB-“切换桢”四、上下文切换的活动五、引起线程上下文切换的原因前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了…

3D Guassians Splatting相关解读

从已有的点云模型出发&#xff0c;以每个点为中心&#xff0c;建立可学习的高斯表达&#xff0c;用Splatting即抛雪球的方法进行渲染&#xff0c;实现高分辨率的实时渲染。 1、主要思想 1.引入了一种各向异性&#xff08;anisotropic&#xff09;的3D高斯分布作为高质量、非结…

查看centos的CPU、内存、磁盘空间等配置信息

目录 查看CPU/proc/cpuinfo中的信息 查看内存/proc/meminfo中的信息 查看磁盘空间df 命令du命令使用fdisk命令 查看CPU /proc/cpuinfo中的信息 前置&#xff1a; [ltkjltkj front]$ cat /proc/cpuinfo| grep "physical id" physical id : 0 physical id : 0 physi…

智慧校园大数据平台架构

平台架构 基础硬件层 基础硬件层是由一组低廉的PC或服务器组合构建而成。基础硬件层主要承载着数据的存储、运算、容错、调度和通信等任务,对基础应用层下达的指令进行执行和反馈。 数据集成 大数据特征表现在实时、交互、海量等方面,并且以半结构化、非结构化数据为主,价…

机器学习系统或者SysMLDL笔记

在使用过TVM、TensorRT等优秀的机器学习编译优化系统以及Pytorch、Keras等深度学习框架后&#xff0c;总觉得有必要从理论上对这些系统进行一些分析&#xff0c;虽然说在实践中学习是最快最直接的(指哪儿打哪儿、不会哪儿查哪儿)&#xff0c;但恶补一些关于系统设计的一些知识还…

搜索经典题——填充 9*9矩阵

题目&#xff1a;给定一个九行九列矩阵&#xff0c;填充矩阵元素&#xff0c;要求&#xff1a; 1、每一行每一列&#xff0c;每个小九宫格&#xff08;图片画粗的地方就是&#xff09;不能包含相同元素 2、每一行&#xff0c;每一列&#xff0c;每个小九宫格均会完整出现1-9的数…

Python进程池multiprocessing.Pool

环境&#xff1a; 鲲鹏920:192核心 内存&#xff1a;756G python&#xff1a;3.9 python单进程的耗时 在做单纯的cpu计算的场景&#xff0c;使用单进程核多进程的耗时做如下测试&#xff1a; 单进程情况下cpu的占用了如下&#xff0c;占用一半的核心数&#xff1a; 每一步…

第二百六十九回

文章目录 概念介绍设置方法示例代码内容总结 我们在上一章回中介绍了Card Widget相关的内容&#xff0c;本章回中将介绍国际化设置.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在这里说的国际化设置是指在App设置相关操作&#xff0c;这样可以让不同国家的…