JUC系列(四) callable与 常用的工具类

【扫地机器人测试】 本测试方案旨在系统性评估扫地机器人的核心功能、性能指标、可靠性及用户体验,验证产品是否符合设计规范、行业标准及市场需求。通过多维度、全场景的测试,精准定位产品缺陷与优化空间,为产品迭代提供数据支撑,确保上市产品的质量稳定性与用户满意度。 阅读详情

📣 📣 📣 📢📢📢
☀️☀️你好啊!小伙伴,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务,数据结构,netty,单点登录,SSM ,SpringCloudAlibaba等
😝公众号😝 : 想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
⏩当前专栏:JUC系列

Callable

image-20220302112839751

callable是什么?

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不容 run() /call()

入门案例

查看源码 我们发现 Thread 类所有的方法参数都是 Runnable 那我们怎么样可以使用callble呢?

image-20220302113326707

思路图:

image-20220302113344057

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //new Thread(new Runnable()).start();
        //new Thread(new FutureTask<V>()).start();
        //new Thread(new FutureTask<V>(callable)).start();
        //怎么启动callable
        new Thread().start();
        MyThread thread = new MyThread();
        //适配类
        FutureTask futureTask = new FutureTask(thread);
        new Thread(futureTask, "A").start();

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

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("call()");
        return 123;
    }
}

细节

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //new Thread(new Runnable()).start();
        //new Thread(new FutureTask<V>()).start();
        //new Thread(new FutureTask<V>(callable)).start();
        //怎么启动callable
        new Thread().start();
        MyThread thread = new MyThread();
        //适配类
        FutureTask futureTask = new FutureTask(thread);
        new Thread(futureTask, "A").start();
        new Thread(futureTask, "B").start();

        // get 接口 可能会产生阻塞
        Integer o = (Integer) futureTask.get();
        System.out.println(o);
    }

这里我们用两个对象,他会输出几次?

image-20220302114220524

一次,为什么呢? 源码会告诉我们答案

 public void run() {
  //这里的判断 如果state 不是new 那么就会return   
        if (state != NEW ||
            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

很明显,我们两次开启的线程但是futureTask只会有一个线程run完,新开的话就会检测到状态不是new 就会return

常用辅助类

CountDownLatch

线程减法计数器 递减

image-20220302135542300

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

常用方法

public void countDown()

递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.

public boolean await(long timeout,TimeUnit unit) throws InterruptedException

使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。

如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直出于休眠状态, 由于调用countDown()方法,计数到达零;或者其他某个线程中断当前线程;或者已超出指定的等待时间。

  • 如果计数到达零,则该方法返回true值。
  • 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
  • 如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。

简单入门案例

//计数器
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        //    总数是六
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "go out");
                //数量-1
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        //等待计数器归零
        countDownLatch.await();
        System.out.println("Close door");
    }
}

countDownLatch.countDown(); // 数量-1

countDownLatch.await(); //等待计数器归零

每次有线程调用countDown 数量 -1 假设计数器变为0,countDownLatch.await()就会被唤醒;继续执行

CyclicBarrier

线程 计数器 递增,是函数式接口

构造器

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

parties 是参与线程的个数

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

重要方法

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException

解析:

  • 线程调用 await() 表示自己已经到达栅栏
  • BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时

代码案例

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        /*集齐七龙珠 召唤神龙
         * 召唤龙珠线程
         * Cyclicbarrier 是函数式接口 ,所以我们可以直接用 lamba
         * */
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙成功");
        });

        for (int i = 1; i <= 7; i++) {
            final int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "收集" + temp + "个龙珠");
                //等待
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

SemaPhore

Semaphore 通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。

举例理解

可以把它简单的理解成我们停车场入口立着的那个显示屏,每有一辆车进入停车场显示屏就会显示剩余车位减1,每有一辆车从停车场出去,显示屏上显示的剩余车辆就会加1,当显示屏上的剩余车位为0时,停车场入口的栏杆就不会再打开,车辆就无法进入停车场了,直到有一辆车从停车场出去为止。

image-20220302142104753

使用场景

通常用于那些资源有明确访问数量限制的场景,常用于限流 。

比如:数据库连接池,同时进行连接的线程有数量限制,连接不能超过一定的数量,当连接达到了限制数量后,后面的线程只能排队等前面的线程释放了数据库连接才能获得数据库连接。

比如:停车场场景,车位数量有限,同时只能容纳多少台车,车位满了之后只有等里面的车离开停车场外面的车才可以进入。

常用方法

acquire()  
获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。

acquire(int permits)  
获取一个令牌,在获取到令牌、或者被其他线程调用中断、或超时之前线程一直处于阻塞状态。
    
acquireUninterruptibly() 
获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。
    
tryAcquire()
尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。

tryAcquire(long timeout, TimeUnit unit)
尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。

release()
释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。

hasQueuedThreads()
等待队列里是否还存在等待线程。

getQueueLength()
获取等待队列里阻塞的线程数。

drainPermits()
清空令牌把可用令牌数置为0,返回清空令牌的数量。

availablePermits()
返回可用的令牌数量。

代码案例

public class SemaPhoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                //得到
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //释放车位
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

【漏洞复现】Apache Tomcat远程代码执行漏洞(CVE-2024-56337) CVE-2024-56337是一个存在于Apache Tomcat中的TOCTOU(Time-of-Check Time-of-Use)竞争条件漏洞。此漏洞源于对先前漏洞(CVE-2024-50379)的不完整修复。若默认servlet是可写的(参数readonly设置值为false,该设置为非默认设置)表示不区分大小写文件系统,在负载下并发读取和上传同一文件可以绕过Tomcat的大小写检查。攻击者可以通过构造恶意请求上传含恶意JSP代码的文件,使其触发解析并执行这些文件,从而导致远程代码执行。 阅读详情

相关推荐

CentOS 7.9安装python3.11

CentOS 7.9安装python3.11

leafseelight的专栏 1343

JUC面试(十)——线程池&Callable接口

线程池做的主要工作就是控制运行的线程的数量,处理过程中,将任务放入到队列中,然后线程创建后,启动这些任务,如果线程数量超过了最大数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。

qq_43409401的博客 1661

Word中 Go to endnote 出现闪退问题解决办法

Word中 Go to endnote 出现闪退问题解决办法

努力努力努力 1万+

[进阶]Java:线程池、处理Runnable、Callable任务、使用Executors得到线程池

System.out.println(Thread.currentThread().getName() + "===> 输出666~");// 线程池会自动创建一个新线程,自动处理这个任务,自动执行的!// 线程池会自动创建一个新线程,自动处理这个任务,自动执行的!// 线程池会自动创建一个新线程,自动处理这个任务,自动执行的!// 等着线程池的任务全部执行完毕后,再关闭线程池。//计算密集型的任务:核心线程数量 = CPU的核数 + 1。// 描述线程的任务,返回线程执行返回后的结果。

m0_68783582的博客 1569

用Stata复现经典文献:上市公司全要素生产率(TFP)计算全流程(含LP/OP代码解读)

本文提供了使用Stata软件复现上市公司全要素生产率(TFP)计算的完整实战指南。重点解读了主流的Levinsohn-Petrin(LP)和Olley-Pakes(OP)半参数估计方法,通过详细的数据清洗、变量构建与价格平减步骤,手把手演示了如何准确测算TFP,并强调了LP方法在处理中国上市公司数据时的稳定性和适用性。

b0c1d2的博客 596

Avalonia v11实战:手把手教你从零创建第一个跨平台桌面App(含设计器不显示的解决方案)

本文详细介绍了如何使用Avalonia v11从零开始创建跨平台桌面应用,包括环境准备、项目创建、界面设计及常见问题解决方案。特别针对设计器不显示等常见问题提供了实用解决方法,帮助.NET开发者快速掌握这一强大的UI框架,实现Windows、macOS和Linux多平台应用开发。

weixin_30417487的博客 164

JUC(三) Callable和 常用的辅助类

Callable 官方文档:Callable接口类似于Runnable ,因为它们都是为其实例可能由另一个线程执行的类设计的。 然而, Runnable不返回结果,也不能抛出被检查的异常。 可以有返回值 可以抛出异常 方法不同,run() / call() 调用Callable FutureTask futureTask = new FutureTask<>(c); //适配类 new Thread(futureTask,"A").start(); publ...

weixin_45729272的博客 214

从零组装一台会‘看’的无人机:手把手教你配置NUC机载电脑与D435深度相机(环境搭建篇)

本文详细介绍了如何从零开始组装一台具备视觉能力的智能无人机,重点讲解了NUC机载电脑与D435深度相机的配置方法。通过Ubuntu系统安装、ROS环境搭建、深度学习框架配置等步骤,帮助开发者实现无人机的自主避障和目标跟踪功能。文章还提供了性能优化和常见问题解决方案,是无人机视觉系统开发的实用指南。

weixin_30915275的博客 398

Java Callable用法

Java Thread ExecutorService Callable Runnable  Callable 和 Runnable 的使用方法大同小异, 区别在于:  1.Callable 使用 call() 方法, Runnable 使用 run() 方法  2.call() 可以返回值, 而 run()方法不能返回。  3.call() 可以抛出受检查的异常,比如Clas

Levin的专栏 1763

kemeas算法继续优化——elkan kmeas算法

题记:又是凌晨3点的夜 elkan kmeans算法 在我的上一篇博客《kmeans算法性能改进_kmeans++算法+kmeans++优化算法+距离计算优化》中,在一般kmeans算法的基础上,添加了对于初始条件和距离计算更上的一些优化技巧。这篇博客聊一聊elkan算法,其实也是对于kmeans运行速度的优化算法。主要作用与kmeans的距离计算过程。 原理 假如我们已经知道任意两个样本之间的距离,再假设我们已经知道了样本1与聚类中心1之间的距离,根据三角性两边之和大于第三边,c+d>a,所以如果

铁血军的小博客 7065

华为OD机试双机位C卷-用户入网定期复评(C/C++/Py/Java/Js/Go)

华为OD机试(机考)双机位C卷 【用户入网定期复评】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【用户入网定期复评】。

qq_45776114的博客 840

除了Thread和Runnable,你还知道第三种创建线程的方式Callable吗

相信大多数学过多线程的同学都知道创建线程常见的有三种方式,一种是继承Thread类,一种是实现Runnable接口,最后一种就是Callable,今天主要是对最后不常见的Callable方式进行介绍。 一、为什么要Callable接口 既然有了前面两种接口,为什么还需要第三种呢?这是因为前两种方式存在着一种缺陷,我们先来看看前面两种实现的方式,然后再来揭晓: class MyThread exte...

冯冬冬的博客 1万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【并发编程】JUC并发编程(彻底搞懂JUC)

JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称,其结构如下:这个包下都是Java处理线程相关的类,自jdk1.5后出现。目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题!JUC主要是指JDK8中java.util.concurrent里提供的一系列线程并发工具,但是线程并发的问题远不止几个工具这么简单。要学习工具使用,更要能深入理解工具的原理以及处理线程并发问题的思路。

DreamSun的博客 7613

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

JUC并发编程

JUC并发编程 JUC简介 进程、线程的关系 Java默认有两个线程 线程的六种状态 并发、并行的关系: Lock锁 Synchronized 和 Lock的区别 8锁现象 问题一 : 在标准情况下,两个线程先打印 发短信 还是 打电话 ? 问题二 : 在发短信方法中,延迟4秒,两个线程先打印 发短信 还是 打电话? 问题三 : Phone类增加一个普通方法,线程B调用,那么两个线程先打印 发短信

识时务者的个人博客 14万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

JUC系列(一)什么是JUC?

多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样的。 先看张图,舒缓下心情,再继续吧 一、JUC简介 JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称。这个包下都是Java处理线程相关的类,自jdk1.5后出现。 二、进程与线程 2.1、进程 概述: 进程(Process) 是计算机中的程序关于某数据集合上的一.

北 3662

【Java EE 初阶】JUC常见工具类介绍

个选手依次就位,哨声响才同时出发;所有选手都通过终点,才能颁奖。操作中的加减计数器操作都是原子的。可以在多线程环境下直接使用。阻塞等待所有任务执行完毕。内部的计数器同时自减。

m0_57248981的博客 1240

【JUC基础】01. 初步认识JUC

前段时间,有朋友跟我说,能否写一些关于JUC的教程文章。本来呢,JUC也有在我的专栏计划之内,只是一直都还没空轮到他,那么既然有这样的一个契机,那就把JUC计划提前吧。那么今天就重点来初步认识一下什么是JUC,以及一些基本的JUC相关基础知识。

有一只柴犬的专栏 1663

【Java|多线程与高并发】JUC中常用的类和接口

JUC是Java并发编程中的一个重要模块,全称为`Java Util Concurrent`(Java并发工具包),它提供了一组用于多线程编程的工具类和框架,帮助开发者更方便地编写线程安全的并发代码。

云泽野の编程日记 1565

【多线程】面试高频考点!JUC常见类的详细总结,建议收藏!

虽然有线程安全的Hashtable或Collections.synchronizedMap(),但它们加锁的方式比较“粗暴”,运行效率往往不高。JUC中就提供了一个 ConcurrentHashMap 类,它在多线程环境下就有更高的性能,因为它采用了分段锁(segmentation)技术,而不是在整个映射上加锁。这意味着多个线程可以同时进行读取操作,甚至在某些条件下可以同时进行写入操作。

acm_pn的博客 1881

【多线程】JUC中的常见组件

本期内容主要介绍 JUC 中常见的组件 Callable 接口和 ReentrantLock 类的内容,并介绍Callable 与 Runnable 接口的区别和 synchronized 与 ReentrantLock 的区别。

爱编程爱运动的博客 3980

Java多线程之锁优化与JUC常用类

本篇文章将介绍java多线程中有关synchronized关键字的优化手段和JUC中的常见类的使用。所谓的JUC指的就是java.util.concurrent包。

未见花闻的博客 1217

JUC之Callable应用与常用的辅助类

1.Callable应用 CallableTest.java package callable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableTest { public static void main(String[] args) throws

可小辉的博客 413

JUC之Callable接口

Callable 创建线程有四种方式: 继承Thread类 实现Runnable接口 Callable接口 线程池 前两种前面说过了, Runnable接口是比较常用的, 因为在Java中继承是很重要的, 不能随便使用, 但是Runnable接口有一个缺点, run()方法没有返回值, 也就是当线程结束时, 不能返回结果, 为了能返回结果, 在JDK1.5以后出现了Callable接口: @FunctionalInterface public interface Callable<V> {

Y_Ace的博客 2882

Java【多线程】(8)CAS与JUC组件

哈喽大家好吖,不知不觉多线程这一块大骨头终于快要啃完了,今天给大家分享的是CAS以及JUC相关组件,那么废话不多说让我们开始吧。

2301_81073317的博客 3546

JUC学习笔记及拓展

JUC学习笔记及拓展Java JUC1 Java JUC简介2 volatile 关键字-内存可见性2.1 内存可见性2.2 volatile 关键字3 原子变量与CAS算法3.1 原子变量3.1.1 i++的原子性问题3.1.2 原子变量3.2 CAS算法3.2.1 ABA问题3.2.2 CAS在JAVA中底层的实现3.3 原子性与可见性区别4 ConcurrentHashMap4.1 锁粒度4.2 锁分段4.3 其它4.4 写入并复制5 CountDownLatch(闭锁)5.1 概念5.2 方法介绍6

yZzc_XQ的博客 3925

【多线程】JUC的常见类 | Callable接口 | ReentranLock | 线程安全的集合类

​ 发现需要扩容的线程, 只需要创建一个新的数组, 同时只搬几个元素过去. 扩容期间, 新老数组同时存在. 后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运一小部分元素. 搬完最后一个元素再把老数组删掉. 这个期间, 插入只往新数组加. 这个期间, 查找需要同时查新数组和老数组。可以通过配置文件来描述配置的详细内容(文件本身不是很大),配置的内容就会被读到内存中,再由其他的线程,来读取这里的内容。只有在操作同一个链表上的内容时,才会发生线程安全问题。

WengJM的博客 1106
上一篇: JUC系列(三) 不安全的集合类
下一篇: 快速入门RabbitMQ并且加入项目实战
冷环渊
博客等级 码龄7年 1130粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冷环渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值