(Java高级教程)第二章Java多线程常见面试题-第二节:JUC(java.util.concurrent)

news2024/11/19 18:40:24

文章目录

  • 一:Callable接口
  • 二:ReentrantLock
  • 三:原子类
  • 四:信号量Semaphore

JUC:JUC是java.util.concurrent包的简称,目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题

一:Callable接口

Callable接口Callable接口类似于Runnable,也即它的实例也可以像Runnable一样传给线程去执行,但是Runnable不返回结果,也不会抛出受查异常,而Callable与此相反

下面使用"1 + 2 + 3 +…+ 1000"这样一个例子来展示使用Callable和不使用Callable时代码的区别

①不使用Callable 可以看到,这种实现逻辑需要借助一个辅助类,还需要使用一系列加锁、wait等操作,比较繁琐。具体实现方式如下(不唯一)

  • 创建一个类Result,包含一个sum表示最终结果,一个lock表示线程锁对象
  • main方法内先创建Result实例,然后创建一个线程thread,在线程内部计算"1 + 2 + 3 +…+ 1000"
  • 主线程同时使用wait等待线程thread计算结束
  • 当线程thread计算完毕之后,通过notify唤醒主线程,接着主线程打印结果
public class TestDemo {
    static class Result{
        public int sum = 0;
        public final Object lock = new Object();
    }

    public static void main(String[] args) throws InterruptedException {
        Result result = new Result();

        Thread thread = new Thread(){
            @Override
            public void run(){
                int sum = 0;
                for(int i = 1; i <= 1000; i++){
                    sum += i;
                }
                synchronized (result.lock){
                    result.sum  = sum;
                    result.lock.notify();
                }
            }
        };
        thread.start();

        synchronized (result.lock){
            while(result.sum == 0){
                result.lock.wait();
            }
        }

        System.out.println("sum:" + result.sum);

    }
}

在这里插入图片描述

②使用Callable 可以看到,在使用CallableFutureTask之后,代码简化了许多,并且不用手动写线程同步代码了。具体实现方式如下

  • 创建一个匿名内部类实现Callable接口。Callable带有泛型参数,它表示返回值的类型
  • 重写Callable中的 call方法,完成计算并直接通过return返回计算结果
  • 由于Thread的构造方法中不能直接传入Callable,所以还需要用FutureTaskCallable的实例给包装一下
  • 创建线程,在其构造方法中传入FutureTask。此时,线程就会执行FutureTask内部的Callablecall方法,完成计算后结果就被放入到了FutureTask对象中
  • main方法中调用futureTask.get()后就会阻塞等到线程计算完毕,并获取到FutureTask中的结果
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class TestDemo2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 使用Callable来定义一个任务
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for(int i = 1; i <= 1000; i++){
                    sum += i;
                }
                return sum;
            }
        };

        // Thread构造方法不能直接传入Callable,所以需要借助一个中间类
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

        // 创建线程执行任务
        Thread thread = new Thread(futureTask);
        thread.start();

        // 获取线程计算结果
        // get方法会阻塞,直到call方法计算完毕
        System.out.println(futureTask.get());
    }
}

在这里插入图片描述

二:ReentrantLock

ReentrantLock:和Synchronized类似,也是可重入锁,用来实现互斥效果,保证线程安全,相较于Synchronized来说更加灵活,也具有更多的方法。具体来说ReentrantLock有三个用法

  • lock():加锁(如果获取不到就会死等)
  • trylock(超时时间):加锁(如果获取不到锁,在等待一段时间后就会放弃加锁)
  • unlock():解锁
ReentrantLock lock = new ReentrantLock();

lock.lock();
try{
	//working....
}finally{
	lock.unlock(); // 千万不要忘记解锁
}

ReentrantLockSynchronized区别如下

  • Synchronized是一个关键字,是JVM内部实现的;ReentrantLock标准库的一类,是在JVM外实现的
  • Synchronized使用时不需要手动释放锁;ReentrantLock使用时需要手动释放,使用起来更加灵活,但也容易忘记解锁
  • Synchronized在申请锁失败时会死等;ReentrantLock可以通过trylock的方式等待一段时间就放弃
  • Synchronized是非公平锁,ReentrantLock默认为非公平锁,可以通过构造方法传入一个true开启公平锁模式
  • ReentrantLock具有更加强大的唤醒机制
    • Synchronized是通过Objectwait/notify来实现的,每次随机唤醒一个等待的线程
    • ReentrantLock搭配Condition类实现,可以精确控制唤醒某个指定的线程

ReentrantLockSynchronized如何选择

  • 锁竞争不激烈的时候使用Synchronized:效率会更高,自动释放也方便
  • 锁竞争激烈的时候使用ReentrantLock:可以搭配trylock更灵活地控制加锁行为,而不至于死等
  • 如果需要公平锁则使用ReentrantLock

三:原子类

原子类:原子类内部通过CAS实现(前文已讲过),所以性能要比加锁实现i++高很多,主要有以下几个

  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicLong
  • AtomicReference
  • AtomicStampedReference

AtomicBoolean为例,涉及方法有

  • addAndGet(int delta)i += delta
  • decrementAndGet()--i
  • getAndDecrement()i--
  • incrementAndGet()++i
  • getAndIncrement()i++
public class TestDemo3 {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger count = new AtomicInteger(0);

        Thread thread1= new Thread(){
            @Override
            public void run(){
                for(int i = 0; i < 50000; i++){
                    // 相当于count++
                    count.getAndIncrement();
                }
            }
        };
        Thread thread2= new Thread(){
            @Override
            public void run(){
                for(int i = 0; i < 50000; i++){
                    // 相当于count++
                    count.getAndIncrement();
                }
            }
        };
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

        System.out.println("count:" + count.get());
    }
}

四:信号量Semaphore

  • 信号量属于操作系统重点内容,这里只做简单介绍

信号量:本质就是一个变量(分为整形和记录型两种),表示系统中某种资源的数量。控制信号量有两种原子操作:

  • P操作(wait(S)原语):这个操作会把信号量减去1,相减后如果信号量<0则表示资源已经被占用,进程需要阻塞;相减后如果信号量 ≥ 0 \ge0 0,则表明还有资源可以使用,进程可以正常执行
  • V操作(signal(S)原语):这个操作会把信号量加上1,相加后如果信号量 ≤ 0 \le0 0,则表明当前有阻塞中的进程,于是会把该进程唤醒;相加后如果信号量>0,则表明当前没有阻塞中的进程

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

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

相关文章

智己LS7发布,预售价格区间35-50万元

12月20日&#xff0c;智己首款中大型大五座SUV 智己LS7开启预售。动力配置&#xff1a; •最大零百加速4.5S&#xff1b; •峰值公里425kw&#xff0c;峰值扭矩725Nm&#xff1b; •提供90度和100度电池选项&#xff1b; •最大CLTC续航660km&#xff1b;空间配置&#xff1a; …

06. http协议基础,带你了解网络访问

06. http协议基础&#xff0c;带你了解网络访问 渗透测试学习路径 计算机基础网络基础WEB漏洞渗透测试 渗透测试和WEB安全漏洞的区别&#xff1f; 渗透测试包含WEB安全漏洞 WEB网站只是单一的网站服务&#xff0c;在渗透测试过程中可能不是攻击网站&#xff0c;而是寻找其他…

ElasticSearch全文检索原理及过程

倒排索引 ElasticSearch的搜索引擎中&#xff0c;每个文档都有一个对应的文档 ID&#xff0c;文档内容被表示为一系列关键词的集合。例如文档 1 经过分词&#xff0c;提取了 20 个关键词&#xff0c;每个关键词都会记录它在文档中出现的次数和出现位置。那么&#xff0c;倒排索…

差分---(小明的彩灯)蓝桥杯真题,差分思想很明确的模板

小明的彩灯题目描述暴力解法差分的思路和模板差分解法题目描述 小明拥有 N个彩灯&#xff0c;第 i个彩灯的初始亮度为 ai​。 小明将进行 Q次操作&#xff0c;每次操作可选择一段区间&#xff0c;并使区间内彩灯的亮度 x&#xff08;x可能为负数&#xff09;。 求 Q次操作后…

自动控制原理笔记-传递函数

目录 拉普拉斯反变换&#xff1a; 用拉普拉斯变换求解常微分方程的步骤&#xff1a; 部分分式展开法&#xff1a; 留数法&#xff1a; 零极点图: 传递函数 定义&#xff1a; 传递函数的标准形式&#xff1a; 传递函数的性质&#xff1a; 传递函数的局限性&#xff1a…

SOT23-6封装 小封装 超精简外围PD Sink端取电协议芯片

PD协议&#xff08;USB-PD&#xff09;的全名是USB Power Delivery&#xff0c;是由 USB-IF 组织制定的一种快速充电规范&#xff0c;是目前主流的快充协议之一&#xff0c;USB-PD 快充协议是以 Type-C 接口输出的&#xff0c;我们经常看到的华为笔记本配的Type-C 65W充电器就是…

【C语言】函数栈帧的创建和销毁

目录 1.函数栈帧的含义 概念 要用到的汇编语言的知识 示例 2.理解栈帧 2.1 main函数栈帧的创建 2.2 局部变量的创建 2.3 函数传参 2.4 调用函数 2.5 函数返回 一个.c文件在调用函数的时候&#xff08;包括main 函数&#xff09;&#xff0c;其内存中的栈区有什么变…

Qt之实现工具箱界面程序

最近终于有点空闲时间了&#xff0c;就写写博客&#xff0c;就把上次给客户实现的一个程序开发过程写出来&#xff1b;客户要求的是在主界面上能有几个很好看的按钮&#xff0c;单击各个按钮能弹出不同的应用窗口&#xff0c;如游戏窗口&#xff0c;显示图像窗口等等&#xff0…

pcl 基本操作汇总

目录 PCLVisualizer简单的点云可视化 createViewPort创建视窗 代码 效果 点云视窗上打印文本信息 使用addText 合并多个点云 xyzxyz xyz nxnynz 新建自己的Point类型 点云的刚体变换&#xff08;旋转平移&#xff09; 以下是pcl点云基本操作&#xff0c;后面会慢慢…

C++--数据结构--最小生成树-- Kruskal--Prim--高阶0713

注&#xff1a;本次修改了添加边的一些其他情况可以采用坐标来添加边 void _AddEdge(size_t srci, size_t dsti, const W& w) {_matrix[srci][dsti] w;// 无向图if (Direction false){_matrix[dsti][srci] w;} }void AddEdge(const V& src, const V& dst, const…

【学习笔记03】vue的组件

目录一、组件二、组件的分类&#xff08;一&#xff09;全局组件&#xff08;二&#xff09;局部组件1、为什么vue组件 data函数返回一个对象2、bootstrap的使用三、父组件传值给子组件1、父传子实现进度条2、 props的属性四、子组件传值给父组件五、兄弟组件传值一、组件 可以…

【Javassist】快速入门系列04 使用Javassist更改整个方法体

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 文章目录系列文章目录前言引入Javassist jar包使用Javassist更改整个方法体总结说明前言 上一章我们介绍了使用Javas…

2022全年度白酒十大热门品牌销量榜单

白酒为中国特有的一种蒸馏酒&#xff0c;是世界六大蒸馏酒之一&#xff0c;中国是全球最大的蒸馏酒市场&#xff0c;中国的白酒消费也位列世界烈酒行业领先地位。近几年来&#xff0c;由于市场需求的不断提升及居民的消费升级&#xff0c;高档白酒价格也不断增长&#xff0c;从…

会员管理系统可行性研究

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 1.引言 1.1编写目的 1.2项目背景 1.3定义 1.4参考资料 2.可行性研究前提 2.1要求 2.2目标 2.3条件、假定和限制 2.4决定可行性的因素 3.现有小程序分析 3.1经…

进程-计算机是如何工作的

文章目录冯诺依曼计算机体系组成寄存器和内存编译型语言vs解释型语言进程进程管理进程的状态虚拟地址空间虚拟内存冯诺依曼计算机体系 组成 (1) 输入设备:键盘&#xff0c;鼠标 (2) 输出设备:显示器&#xff0c;打印机 其中硬盘(可做输入、输出) (3) 存储器:内存 (4) CPU 运…

Composing Programs(SICP python版) chap1 笔记

《Composing Programs》(SICP python版) chap1 笔记 持续更新中 在学习 CS61A 2022fall的时候配着看的 文章目录《Composing Programs》(SICP python版) chap1 笔记Chapter 1: Building Abstractions with Functions1.1 Getting Started1.1.1 Programming in Python1.1.2 Insta…

python安装face_recognition

本人使用系统为windows10,python的版本是3.8&#xff0c;在安装face_recognition之前需要安装以下内容&#xff1a; 1.cmake 2.dlib&#xff0c;dlib的安装依赖于cmake 1 安装CMake 1.1 官网下载&#xff1a;CMake 1.2 开始安装CMake: 1.3 验证是否安装成功&#xff1a; 打开…

10 Mysql中各种锁

概述 MySQL中的也存在一些类型的锁&#xff0c;用来保证多个连接同时操作数据时的安全即数据的一致性问题&#xff1b;同时&#xff0c;虽然锁能够解决一些数据的一致性和有效性&#xff0c;但是我们还是要选择合适的锁来降低锁对于并发问题的影响 1. 全局锁 全局锁就是对整…

傻白探索Chiplet,互连技术研究现状(七)

目录 一、串行互连 二、并行互连 三、串行与并行互连的比较 四、互连标准接口 &#xff08;1&#xff09;背景 &#xff08;2&#xff09;UCIe Chiplet的可行性常常受到片间互连的性能、可用性以及功耗和成本问题的限制&#xff0c;各种异构芯片的互连接口和标准的设计在技…

Web3中文|恐惧vs伦理:AI艺术评论家错在哪里?

本周&#xff0c;人工智能引发众怒。随着“AI艺术”在网络的流行&#xff0c;一群艺术家正在知名艺术家平台Art Station上掀起一场反AI艺术的抗议活动&#xff0c;而人工智能技术的拥趸者也及时回击了这波反对热潮。 这种充斥着反对意见的热潮是迟早会出现的。现在这些人认为“…