JUC(java.util.concurrent) 的常见类

Callable 接口

Callable 的用法

        Callable 是一个 interface(类似之前的 Runnable,用来描述一个任务,但是没有返回值)也是描述一个任务的,有返回值。方便程序猿借助多线程的方式计算结果.

例如:创建线程计算 1 + 2 + 3 + ... + 1000, 不使用 Callable 

        创建一个类 Result , 包含一个 sum 表示最终结果, lock 表示线程同步使用的锁对象. main 方法中先创建 Result 实例, 然后创建一个线程 t. 在线程内部计算 1 + 2 + 3 + ... + 1000. 主线程同时使用 wait 等待线程 t 计算结束. (注意, 如果执行到 wait 之前, 线程 t 已经计算完了, 就不必等待了). 当线程 t 计算完毕后, 通过 notify 唤醒主线程, 主线程再打印结果.

static class Result {
   public int sum = 0;
   public Object lock = new Object();
}
public static void main(String[] args) throws InterruptedException {
   Result result = new Result();
   Thread t = 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();
          }
      }
  };
   t.start();
   synchronized (result.lock) {
       while (result.sum == 0) {
           result.lock.wait();
      }
       System.out.println(result.sum);
  }
}

使用 callable 

        创建一个匿名内部类, 实现 Callable 接口. Callable 带有泛型参数. 泛型参数表示返回值的类型. 重写 Callable 的 call 方法, 完成累加的过程. 直接通过返回值返回计算结果. 把 callable 实例使用 FutureTask 包装一下. 创建线程, 线程的构造方法传入 FutureTask . 此时新线程就会执行FutureTask 内部的 Callable 的 call 方法, 完成计算. 计算结果就放到了 FutureTask 对象中. 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果.

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

public class ThreadDemo29 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 使用 Callable 来计算 1 + 2 + 3 + ... + 1000
        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;
            }
        };

        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();

        Integer result = futureTask.get();
        System.out.println(result);
    }
}

理解 Callable

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

Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.

FutureTask 就可以负责这个等待结果出来的工作.

理解 FutureTask

        想象去吃麻辣烫. 当餐点好后, 后厨就开始做了. 同时前台会给你一张 "小票" . 这个小票就是

FutureTask. 后面我们可以随时凭这张小票去查看自己的这份麻辣烫做出来了没.

相关面试题

介绍下 Callable 是什么

Callable 是一个 interface . 相当于把线程封装了一个 "返回值". 方便程序猿借助多线程的方式计算结果.

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

Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.

FutureTask 就可以负责这个等待结果出来的工作.

ReentrantLock

可重入互斥锁. 和 synchronized 定位类似, 都是用来实现互斥效果, 保证线程安全.

ReentrantLock 的用法:

lock(): 加锁, 如果获取不到锁就死等.

trylock(超时时间):加锁, 如果获取不到锁, 等待一定的时间之后就放弃加锁.

unlock():解锁

ReentrantLock 和 synchronized 的区别:

        synchronized 是一个关键字, 是 JVM 内部实现的(大概率是基于 C++ 实现). ReentrantLock 是标准库的一个类, 在 JVM 外实现的(基于 Java 实现)。

        synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活, 但是也容易遗漏 unlock。

        synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间还是获取不到就放弃。

        synchronized 是非公平锁, ReentrantLock 默认是非公平锁. 可以通过构造方法传入一个 true 变成公平锁模式。

        更强大的唤醒机制. synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程。

import java.util.concurrent.locks.ReentrantLock;

public class ThreadDemo30 {
    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock(true); //输入 true 就会变成公平锁
        //reentrantLock 返回值是是否加上了锁
        boolean result = reentrantLock.tryLock(); //括号内可以填参数,表示最大等待时间,如果超过了就放弃锁
        try {
            
        } finally {
            if (result) {
                reentrantLock.unlock();
            }
        }

    }
}

如何选择使用哪个锁?

锁竞争不激烈的时候, 使用 synchronized, 效率更高, 自动释放更方便.

锁竞争激烈的时候, 使用 ReentrantLock, 搭配 trylock 更灵活控制加锁的行为, 而不是死等.

如果需要使用公平锁, 使用 ReentrantLock.

原子类

原子类内部用的是 CAS 实现,所以性能要比加锁实现 i++ 高很多。原子类有以下几个

AtomicBoolean

AtomicInteger

AtomicIntegerArray

AtomicLong

AtomicReference

AtomicStampedReference

以 AtomicInteger 举例,常见方法有

 

线程池

        虽然创建销毁线程比创建销毁进程更轻量, 但是在频繁创建销毁线程的时候还是会比较低效. 线程池就是为了解决这个问题. 如果某个线程不再使用了, 并不是真正把线程释放, 而是放到一个 "池子"中, 下次如果需要用到线程就直接从池子中取, 不必通过系统来创建了.

ExecutorService Executors

代码示例:

ExecutorService 表示一个线程池实例.

Executors 是一个工厂类, 能够创建出几种不同风格的线程池.

ExecutorService 的 submit 方法能够向线程池中提交若干个任务.

ExecutorService pool = Executors.newFixedThreadPool(10); 
pool.submit(new Runnable() {
    @Override
    public void run() { 
        System.out.println("hello");
    }
});

Executors 创建线程池的几种方式

        newFixedThreadPool: 创建固定线程数的线程池

        newCachedThreadPool: 创建线程数目动态增长的线程池.

        newSingleThreadExecutor: 创建只包含单个线程的线程池.

        newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.

Executors 本质上是 ThreadPoolExecutor 类的封装.

ThreadPoolExecutor

ThreadPoolExecutor 提供了更多的可选参数, 可以进一步细化线程池行为的设定.

ThreadPoolExecutor 的构造方法

理解 ThreadPoolExecutor 构造方法的参数

把创建一个线程池想象成开个公司. 每个员工相当于一个线程.

        corePoolSize: 正式员工的数量. (正式员工, 一旦录用, 永不辞退)

        maximumPoolSize: 正式员工 + 临时工的数目. (临时工: 一段时间不干活, 就被辞退).

        keepAliveTime: 临时工允许的空闲时间.

        unit: keepaliveTime 的时间单位, 是秒, 分钟, 还是其他值.

        workQueue: 传递任务的阻塞队列

        threadFactory: 创建线程的工厂, 参与具体的创建线程工作.

        RejectedExecutionHandler: 拒绝策略, 如果任务量超出公司的负荷了接下来怎么处理.

        AbortPolicy(): 超过负荷, 直接抛出异常.

        CallerRunsPolicy(): 调用者负责处理

        DiscardOldestPolicy(): 丢弃队列中最老的任务.

        DiscardPolicy(): 丢弃新来的任务.

线程池的工作流程:

信号量 Semaphore

信号量, 用来表示 "可用资源的个数". 本质上就是一个计数器.

        可以把信号量想象成是图书馆中某一本书的在馆数: 当前在馆 100 本. 表示有 100 个可用资源。当有书接进去的时候, 就相当于申请一个可用资源, 可用在馆数就 -1 (这个称为信号量的 P 操作) 当有人还书的时候, 就相当于释放一个可用资源, 可用在馆数就 +1 (这个称为信号量的 V 操作)如果计数器的值已经为 0 了, 还尝试申请资源, 就会阻塞等待, 直到有其他线程释放资源.

        锁,可以视为是计数器为 1 的信号量,只有 0 和 1 这两种取值(二元信号量)。

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

P 操作:申请一块可用资源,计数器就要 - 1

V 操作:释放一个可用资源,计数器就要 + 1

 具体的使用:

import java.util.concurrent.Semaphore;

public class ThreadDemo31 {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(3);
        semaphore.acquire();
        System.out.println("执行一次 P 操作");
        semaphore.acquire();
        System.out.println("执行一次 P 操作");
        semaphore.acquire();
        System.out.println("执行一次 P 操作");
        semaphore.acquire();
        System.out.println("执行一次 P 操作");

        semaphore.release();
    }
}

CountDownLatch

        同时等待 N 个任务执行结束. 好像跑步比赛,10个选手依次就位,哨声响才同时出发;所有选手都通过终点,才能比赛结束。

为了做到等待所有都到达终点,主要是采用两种方法:

1. await(a → all),主线程调用这个方法

2. countDown 表示选手冲过了终点线

        CountDownLatch 在构造的时候,会指定一个计数(选手的个数)。就像上述十位选手进行比赛,初始情况下会调用 await 然后就会阻塞,每个选手冲过终点都会调用 countDown 方法,前 9 次调用 countDown,await 没有任何影响,第十次调用的时候,await 就会被唤醒,然后返回解除阻塞。此时就认为整个比赛都结束了。

相关面试题

1) 线程同步的方式有哪些?

synchronized, ReentrantLock, Semaphore 等都可以用于线程同步.

2) 为什么有了 synchronized 还需要 juc 下的 lock?

以 juc 的 ReentrantLock 为例,

        synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活,synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间就放弃.

        synchronized 是非公平锁, ReentrantLock 默认是非公平锁. 可以通过构造方法传入一个true 开启公平锁模式.

        synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程.

3) AtomicInteger 的实现原理是什么?

基于 CAS 机制. 伪代码如下:

class AtomicInteger {
    private int value;
    public int getAndIncrement() {
         int oldValue = value;
         while ( CAS(value, oldValue, oldValue+1) != true) {
             oldValue = value;
         }
         return oldValue;
    }
}

4) 信号量听说过么?之前都用在过哪些场景下?

        信号量, 用来表示 "可用资源的个数". 本质上就是一个计数器.

        使用信号量可以实现 "共享锁", 比如某个资源允许 3 个线程同时使用, 那么就可以使用 P 操作作为加锁, V 操作作为解锁, 前三个线程的 P 操作都能顺利返回, 后续线程再进行 P 操作就会阻塞等待,直到前面的线程执行了 V 操作.

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

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

相关文章

CZT Blusetein‘s FFT

参考文献&#xff1a; [Sto66] Stockham Jr T G. High-speed convolution and correlation[C]//Proceedings of the April 26-28, 1966, Spring joint computer conference. 1966: 229-233.[Blu68] Bluestein L. A linear filtering approach to the computation of discrete …

代码优化实践之税率计算问题

开篇 今天的问题来自于《编程珠玑》第三章【数据决定程序结构】&#xff0c;这里提出了几条代码优化相关的原则&#xff0c;受益不浅。下面是提到的几条原则&#xff1a; 使用数组重新编写重复代码。冗长的相似代码往往可以使用最简单的数据结构——数组来更好的表述&#xff1…

Vue3: toRefs与toRef的基本使用

一、前言 本文主要介绍toRefs与toRef的基本使用。 二、内容 1、基本概念 作用: toRefs与toRef可以将一个响应式对象中的每一 个属性&#xff0c;转换为ref对象&#xff1b;不同 toRefs与toRef功能一致&#xff0c;但toRefs可以批量转换。 2、toRefs 如果把reactive定义的…

ROS仿真小车(四)—— URDF与Gazebo集成

文章目录 前言一、ubuntu20.04中下载gazebo_models二、在gazebo中显示简单模型1 创建功能包&#xff0c;导入依赖2 编写URDF文件3 编写launch文件4 在gazebo中显示机器人模型 三、URDF集成Gazebo相关设置四、在gazebo中导入小车模型1 编写xacro文件2 编写launch文件3 运行结果 …

Stable Diffusion 模型分享:MeinaMix(动漫)meinamix_meinaV11

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 MeinaMix 的目标是&#xff1a;能够在很少的提示下…

SpectralMamba:用于高光谱图像分类的高效 Mamba

SpectralMamba&#xff1a;用于高光谱图像分类的高效 Mamba 摘要IntroductionMethodologyPreliminariesSpectralMamba: OverviewSpectralMamba: Key ComponentsB1 Piece-wise Sequential ScanningIii-B2 Gated Spatial-Spectral Merging SpectralMamba: Efficient Mamba for Hy…

【InternLM 实战营第二期作业06】Lagent AgentLego 智能体应用搭建

基础作业 1.完成 Lagent Web Demo 使用 使用 LMDeploy 部署 conda activate agent lmdeploy serve api_server /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-7b \--server-name 127.0.0.1 \--model-name internlm2-chat-7b \--cache-max-entry-count 0.1 …

Linux文件的特殊权限(SUID|SGID|SBIT)

一、SUID 介绍&#xff1a;SUID是一种对二进制程序进行设置的特殊权限&#xff0c;能够让二进制程序的执行者临时拥有所有者的权限&#xff08;仅对拥有执行权限的二进制程序有效&#xff09;。 &#xff08;一&#xff09;语法格式 chmod us 文件名&#xff08;设置SUID权限…

SOLIDWORKS批量改名工具个人版 慧德敏学

每个文件都会有自己的名字&#xff0c;SOLIDWOKRKS模型也不例外。但是如果从资源管理器直接修改模型的文件名&#xff0c;就会导致模型关联的丢失&#xff0c;导致装配体打开之后找不到模型&#xff0c;因此就需要使用SOLIDWORKS的重命名功能。 SOLIDWORKS批量改名插件- Solid…

智能电网线路阻抗模拟器基础认识

智能电网线路阻抗模拟器是专门用于模拟电力系统输电线路阻抗特性的装置&#xff0c;它能够根据设定的参数&#xff0c;精确地模拟出各种不同类型、不同长度和不同截面积的输电线路在正常运行或故障状态下的阻抗特性。这种模拟器在电力系统的规划、设计、运行和维护中起着重要的…

交换机的种类有哪些?主要都具有哪些作用?

在当今数字化时代&#xff0c;网络已经成为我们生活和工作中不可或缺的一部分。无论是家庭网络还是企业网络&#xff0c;都需要有效的网络设备来实现数据通信和资源共享。而网络交换机作为一种重要的网络设备&#xff0c;扮演着连接和管理网络设备的关键角色。本文将探讨交换机…

TXT文本编辑器,高效将文本里特定符号前的内容作为关键词一键复制或移动文件,效管理文件内容

在日常工作和生活中&#xff0c;我们经常需要处理大量的文件&#xff0c;而文件的管理和整理则成为了一个重要的问题。传统的文件管理方式不仅效率低下&#xff0c;而且容易出错。为了解决这一难题&#xff0c;我们推出了一款强大的TXT文本编辑器&#xff0c;它能够帮助你以文件…

岩石变角剪切试验夹具 技术参数

岩石变角试验夹具是根据TB10115-2014铁路工程岩石试验规程等标准利用压力机施加垂直荷载,通过一套特制的夹具使试件沿某一剪切面产生剪切破坏,然后通过静力平衡条件解析剪切面上的法向压应力和剪应力,从而绘制法向压应力&#xff08;σ&#xff09;与剪应力&#xff08;τ&…

flutter release 报错 Error: SocketException: Failed host lookup:

flutter 的 debug 模式没有任何问题 &#xff0c;打了release 包后一直报下面的错&#xff0c;查了一下是 因为没有网络权限 Error: SocketException: Failed host lookup: yomi-test-aws-sg.yomigame.games (OS Error: No address associated with hostname, errno 7) 按照下…

YOLOv5 / YOLOv7 / YOLOv8 / YOLOv9 / RTDETR -gui界面-交互式图形化界面

往期热门博客项目回顾&#xff1a;点击前往 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 AI健身教练-引体向上…

使用 大模型快速生成-jsToJava 的正则表达式离线版本的简单html页面

注意&#xff1a;需求要描述清楚-提高程序员的工作效率 代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0&quo…

C++相关概念和易错语法(6)(运算符重载)

1.运算符重载注意事项&#xff1a; &#xff08;1&#xff09;多个同一运算符重载可构成函数重载 &#xff08;2&#xff09;在成员函数中由于隐含了this指针&#xff0c;外部调用看上去前置和后置不会有任何区别&#xff0c;所以为了区分这个在后置时强制引入参数int&#x…

医药行业如何巧用AI智能客服机器人?看完你就会了

我们都知道&#xff0c;医药行业信息量庞大&#xff0c;行业规范严格&#xff0c;客户查询和服务需求复杂多变。那么&#xff0c;医药企业该如何高效响应客户&#xff0c;同时保持服务质量并降低成本呢&#xff1f;答案很可能就在AI智能客服机器人。 AI智能客服机器人利用人工智…

【鸿蒙NEXT】web组件debug模式

官方文档 使用Devtools工具调试前端页面 打开web debug模式 webview.WebviewController.setWebDebuggingAccess(true)chrome 访问 chrome://inspect/#devices Discover network targets 中添加 localhost:9222 创建cat.sh name$(hdc shell ps -ef | grep com.cib.qdzg | …

js作业微博发言

微博 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" content&q…