JUC的常见类

2024-01-21

目录

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("所有任务都已执行完成");
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JUC的常见类 的相关文章

  • Java 迭代器获取下一个而不递增

    我正在用 Java 编写以下循环 对于每个循环 我想访问链表 r 的当前元素和下一个元素 List
  • Gson.toString() 给出错误“IllegalArgumentException:多个名为 mPaint 的 JSON 字段”

    我想将自定义对象转换为字符串并保存在 SharedPreferences 中 这是我的最终目标 我尝试了下面的行但失败了 String matchString gson toJson userMatches Logcat 10 11 15
  • 使用比较器对对象进行排序给出空指针

    我正在尝试对包含 3 张卡的 ArrayList 进行排序 我正在用比较器来做这件事 这是否太过分了 Card getRank 返回 2 到 14 之间的整数 我完全不知道哪里出了问题 我之前已经成功完成了这个 并与我的其他代码进行了比较
  • Restlet 和 MULTIPART_FORM_DATA 或通过 Restlet 将文件放在 Google App Engine 上的其他方式

    我尝试通过 Restlet 接收文件 但只获得完整的 MULTIPART FORM DATA 如何提取我的特定文件 我找到了一些代码块 但它们的类型不可用 RESTlet 如何处理多部分 表单数据请求 https stackoverflow
  • 谁能解释一下 servlet 映射吗?

    我正在尝试使用 SpringMVC 编写一个 Web 应用程序 通常我只是将一些虚构的文件扩展名映射到 Spring 的前端控制器并快乐地生活 但这次我要使用类似 REST 的 URL 没有文件扩展名 将我的上下文路径下的所有内容映射到前端
  • Java 弱哈希映射 - 需要根据值的弱点而不是键来删除条目

    所以JavaWeakHashMap让我们创建一个映射 如果其键变弱 则删除该映射的条目 但是我怎样才能创建一个Map 当它的条目被删除时values地图上变弱了 我想使用映射的原因是作为全局哈希表 它根据对象的 ID 跟踪对象 ID gt
  • 使用 Gson 序列化时如何公开类名

    我的场景非常复杂 但总结如下 我试图了解编译器的源代码 并了解每个 AST 节点代表什么 我正在生成不同程序的 AST 的 JSON 序列化 然后检查可视化的 JSON 输出 它工作得很好 除了一个问题是在 Gson 中生成的 JSON 数
  • (Java) 在 Mac OS X 上以编程方式访问“系统根目录”下的 SSL 证书

    我正在编写一个 Java 应用程序 它可以通过远程 Https 站点进行 REST Api 调用 远程站点由受信任的证书签名 它在 Windows 上运行良好 但由于 SSL 证书问题 在 OS X 上运行时遇到问题 我做了一些挖掘 发现原
  • 从 org.w3c.dom.Node 获取 Xpath

    我可以从 org w3c dom Node 获取完整的 xpath 吗 假设当前节点指向 xml 文档中间的某个位置 我想提取该元素的 xpath 我正在寻找的输出 xpath 是 parent child1 chiild2 child3
  • org.hibernate.MappingException:没有 JDBC 类型的方言映射:1111

    我使用的是 postgres v8 3 它的列类型为 XML DDL 看起来像这样 CREATE TABLE contact ID INTEGER NOT NULL NAME VARCHAR NOT NULL Details XML 在映射
  • Java 泛型和数字类型

    我想创建一个通用方法来有效地执行此操作 class MyClass static
  • 为什么 Java 中的 hashCode() 可以对不同对象返回相同的值?

    引用我正在读的书中的一段话首先Java http www amazon co uk Head First Java Kathy Sierra dp 0596009208 关键是 哈希码可以相同 但不一定保证对象相等 因为使用的 哈希算法 h
  • Spring @Value 添加验证小于

    我使用以下属性值注入 我如何向此操作添加小于验证 我的意思是我想设置一个验证user maxpassiveday可以说 财产价值不得低于 100 Value user maxpassiveday int maxpassiveday 使用Sp
  • 如何使用 UUID 生成唯一的正 Long

    我需要为我的数据库主键列生成唯一的长 ID 我以为我可以用UUID randomUUID getMostSignificantBits 但有时它也会产生一些负多头 这对我来说是个问题 是否可以从 UUID 中仅生成正长 将会有数十亿个条目
  • 获取证书链

    我正在 Java 中使用 X509 证书 给定一个证书 是否可以在签名层次结构中找到所有其他证书 直到找到根证书 我有一个证书文件 带有 cer扩展名 我想提取父签名证书 我想继续查找该证书的父证书 直到获得最终的自签名根证书 我已经检查了
  • 如何获取队列中的第 n 个项目?

    我的应用程序中有许多队列和优先级队列 我想轻松访问这些队列中的第 n 个项目 但没有看到使用 API 实现此目的的简单方法 我想我可以创建一个Iterator并迭代到第 n 个元素或使用toArray index 但似乎应该有一个更简单的方
  • 为什么jdk中没有ConcurrentLinkedHashMap类?

    这个问题直接接着问从我之前的问题来看 https stackoverflow com q 12299731 1527084 我想我的第二个问题的答案是否定的 所以我想了解为什么 java util concurrent 包中没有 Concu
  • Android - 保持用户登录状态

    我正在尝试使用 PHP 和 MySQLi for Android 进行登录 我不明白的是如何保持用户登录状态 我看到一个简单的教程 其中有人使用 SQLite 来保护信息 但我不知道这是否真的安全 如何保存用户信息以保持用户登录状态 谢谢
  • WebSocketStompClient 将无法连接到 SockJS 端点

    我正在尝试新的 从版本 4 2 开始 java STOMP 客户端支持 我的出发点是入门指南 使用 WebSocket 构建交互式 Web 应用程序 http spring io guides gs messaging stomp webs
  • 相当于 C# 中 Java 的“ByteBuffer.putType()”

    我正在尝试通过从 Java 移植代码来格式化 C 中的字节数组 在 Java 中 使用方法 buf putInt value buf putShort buf putDouble 等等 但我不知道如何将其移植到 C 我尝试过 MemoryS

随机推荐

  • Node.js Stream API 泄​​漏

    在使用节点流时 我注意到几乎每个教程都会教授以下内容 Get Google s home page require http get http www google com function response The callback pr
  • Strapi Beta 带有用于电子邮件的自定义 Sendgrid 控制器代码

    Strapi beta 的结构改变了插件的架构方式 删除了 plugins 目录 插件现在保存在 node modules 目录中 我正在尝试编写一些自定义代码以在下订单后触发确认电子邮件 在以前版本的 Strapi 中 电子邮件插件目录位
  • 想要在 Twilio Studio 中使用 Whisper

    我想在 Twilio Studio 中使用 Whisper 这可能吗 现在我只使用 Twilio Studio 和 TwiML Bin 我的目标是 用户呼叫我的 Twilio 号码 将呼叫连接至支持团队电话 在开始用户 客户 和支持团队之间
  • Queryable.Any() 返回 null?

    我有一个数据库查找 例如 var configs dbData Configs Where e gt headers Contains e headerId e flag true if configs Any 其中 configs 作为
  • 如何使用 ggplot2 和线性近似拟合和绘制指数衰减函数

    我试图在只有几个时间点的数据上拟合指数衰减函数 我想使用指数衰减方程 http en wikipedia org wiki Exponential decay y y0 e r time 为了比较r数据集和因子之间 或最终的半衰期 我知道使
  • VS2015 中“DateTime”不包含“ToShortDateString”的定义

    在 VS 2015 中创建通用应用程序并尝试在共享项目中使用 DateTime 的 ToShortDateString 方法时出现以下问题 Visual Studio 2015 智能感知将此显示为错误 但应用程序运行良好 只是想知道 这是
  • 外部链接或 url 在phonegap 上不起作用

    我正在尝试使用phonegap 1 1 0 xcode4 和jqtouch 开发一个应用程序 问题是我无法打开任何外部链接 例如 如果我使用此 href 属性编写锚标记 href http www google com 运行应用程序并单击链
  • 卢阿。在文件中搜索字符串并打印第二列

    寻找解决方案来替换 Lua 中的以下命令 grep dhcp range tmp etc dnsmasq conf awk F print 2 tried for line in file lines do if line match th
  • 在 ubuntu 14.04 中升级 openSSH 7.2p

    我有一台运行 Ubuntu 14 04 的服务器 但我有 PCI 要求问题 我已经在我的服务器中安装了 OpenSSH 6 6p1 然后将其升级到 OpenSSH 7 2p 使用以下命令编译代码直接从 OpenSSH 的存储库进行 make
  • 在用户窗体中使用 Office 图标作为命令按钮上的图像

    我正在创建一些在 OutLook 2010 中使用的用户表单 我想利用一些 Office 图标作为各种命令按钮上的图像 无论如何 我是否可以引用 Office 图标 以避免必须使用宏分发 ico 文件 是的 这将为您提供蓝色信息圆圈 Sub
  • 分段错误 - 在 C 中声明和初始化数组

    我对 C 非常陌生 来自 Python Java 和 C 世界 这可能是一个愚蠢的问题 但我遇到了分段错误 struct for storing matrices typedef struct int m int n float elts
  • jsdoc @ 代码块内的字符

    我正在尝试为这样的模块函数编写文档 Usage NgModule imports BrowserModule ThisModule forRoot name Name version 1 0 param config Service con
  • 覆盖javascript中现有对象的函数

    考虑以下代码 mynamespace myclass function this myfunction function alert Original 我想做的是从 mynamespace myclass 声明之外覆盖 myfunction
  • Web 安全漏洞之 OS 命令注入

    什么是 OS 命令注入 上周我们分享了一篇 Web 安全漏洞之 SQL 注入 其原理简单来说就是因为 SQL 是一种结构化字符串语言 攻击者利用可以随意构造语句的漏洞构造了开发者意料之外的语句 而今天要讲的 OS 命令注入其实原理和 SQL
  • 5个步骤,教你瞬间明白线程和线程安全

    记得今年3月份刚来杭州面试的时候 有一家公司的技术总监问了我这样一个问题 你来说说有哪些线程安全的类 我心里一想 这我早都背好了 稀里哗啦说了一大堆 他又接着问 那你再来说说什么是线程安全 然后我就GG了 说真的 我们整天说线程安全 但是对
  • 如何用结构体替代数组实现学生信息的录入与比较

    这里是一个有关学生学号 成绩信息的录入 输出成绩最高的学生信息 供参考学习 include
  • 如何把题库做成答题小程序?

    随着移动互联网的普及 越来越多的人开始使用手机进行学习 而微信小程序作为一种轻量级的应用 受到了越来越多人的青睐 那么 如何把题库做成答题小程序呢 下面就来详细介绍一下 一 搭建题库小程序 首先准备好我们的营业执照 然后选择一个合适的搭建工
  • 2024年华数杯国际赛A题:放射性废水处理建模 思路模型代码解析

    2024年华数杯国际赛A题 放射性废水处理建模 Radioactive Wastewater from Japan 一 问题描述 2011年3月 日本东海岸发生了地震 引发了福岛第一核电站事故 导致三个核反应堆熔毁 并在一场巨大海啸中冲毁了
  • 38条Web测试经验分享

    1 页面链接检查 每一个链接是否都有对应的页面 并且页面之间切换正确 可以使用一些工具 如LinkBotPro File AIDCS HTML Link Validater Xenu等工具 LinkBotPro不支持中文 中文字符显示为乱码
  • JUC的常见类

    目录 Callable ReentrantLock Semaphore CountDownLatch JUC 即 java util concurrent 其中存放了一些进行多线程编程时有用的类 Callable Callable是一个接口