当前位置: 首页 > news >正文

JavaEE中的JUC的常见的类

文章目录

  • JUC
    • 1. Callable接口
    • 2.ReentrantLock
    • 3.原子类
    • 4.线程池
    • 5. 信号量Semaphore
    • 6.CountDownLatch
  • 总结


JUC

JUC => java,util.concurrent 并发

这个包里放的东西都是跟多线程相关的~

1. Callable接口

类似于Runnable.

Runnable描述的任务,不带返回值
Callable描述的任务是带返回值的!!

如果多线程完成的任务,希望带上结果,就使用Callable比较好~

代码实现:
通过Callable创建线程,来计算 1+2+3+…+1000:

public class TeseDemo {
    //创建线程,通过线程来计算 1+2+3+...+1000

    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;
            }
        };

        FutureTask futureTask = new FutureTask<>(callable);

        //创建线程,来执行上述任务
        //Thread的构造方法,不能直接传callable,还需要一个中间的类
        Thread thread = new Thread(futureTask);

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

在这里插入图片描述

FutureTask存在的意义就是为了让我们能够获取到结果(获取到结果的凭证),比如去食堂吃饭的时候,给你一个号,你的做好了,就喊你的号

线程创建的方式:

  1. 继承Thread(可以使用匿名内部类,也可以不用)
  2. 使用 Runnable(可以使用匿名内部类,也可以不用)
  3. 使用 lambda
  4. 使用线程池
  5. 使用 Callable

在这里插入图片描述

2.ReentrantLock

ReentrantLock是可重入互斥锁~

ReentrantLock 也是可重入锁. “Reentrant” 这个单词的原意就是 “可重入”

synchronized 也是可重入锁,但是有一些操作是做不到的,ReentrantLock是对synchronized的一个补充

ReentrantLock核心用法,三个方法:

  1. lock()加锁
  2. unlock()解锁
ReentrantLock locked = new ReentrantLock();
        //加锁
        locked.lock();
        //解锁
        locked.unlock();

这两节之间如果有return或者有异常
就可能导致unlock执行不到了!

synchronized则没有这个问题,只要代码出了代码块,就一定执行解锁~~

在这里插入图片描述
改成这样就可以解决这个问题了~

但是ReentrantLock的优点比缺点更耀眼,它有一些特定的功能,是synchronized做不到的:

  1. tryLock试试看能不能加上锁,试成功,就加锁成功,试失败了,就放弃~ 并且还可以指定加锁的等待超时时间~实际开发中,使用"死等的策略"要慎重,tryLock就提供了更多的可能
  2. ReentrantLock可以实现 公平锁~ 默认是非公平的,构造的时候,传入一个简单参数,就成了公平锁~
    在这里插入图片描述
  3. synchronized是搭配wait/notify 实现等待通知机制的,唤醒操作是随机唤醒一个等待的线程,ReentrantLock是搭配Condition类实现的,唤醒操作可以指定哪个等待的线程的

synchronizedReentrantLock的区别: 缺点+优势

在这里插入图片描述

3.原子类

原子类的底层,是基于CAS实现的,以比较高效的方式完成线程安全的自增自减~

Java里已经封装好了,可以直接来使用
在这里插入图片描述

使用原子类,最常见的场景就是使用多线程计数

🎄🎀比如写了个服务器,要计算一共有多少个并发量,就可以通过这样的原子变量来累加~

原子类的使用代码:

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author YuanYuan
 * @Date 2022/9/25
 * @Time 21:17
 */
public class TestDemo2 {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger count = new AtomicInteger(0);
        Thread t1 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                //相当于count++
                count.getAndIncrement();
//                //相当于++count
//                count.incrementAndGet();
//                //相当于count--
//                count.getAndIncrement();
//                //相当于--count
//                count.decrementAndGet();
            }
        });
        Thread t2 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                //相当于count++
                count.getAndIncrement();
//                //相当于++count
//                count.incrementAndGet();
//                //相当于count--
//                count.getAndIncrement();
//                //相当于--count
//                count.decrementAndGet();
            }
        });
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        //get()获取到内部的值
        System.out.println(count.get());
    }
}


运行结果:
在这里插入图片描述
可以看见没有任何加锁,借助CAS,完成了一个原子的累加。

在这里插入图片描述

4.线程池

JavaEE多线程中的 单例模式与线程池

5. 信号量Semaphore

信号量这个概念是大佬 迪杰斯特拉 提出来的。

信号量的基本操作是两个:

  1. P操作,申请一个资源
  2. V操作,释放一个资源

信号量本身是一个计数器,表示可用资源的个数:

P操作申请一个资源,可用资源数就 - 1
V操作释放一个资源,可用资源数就 + 1

当计数为0的时候,继续P操作,就会产生阻塞,阻塞等待到其他线程V操作了为止~~

基于信号量也是可以实现生产者消费者模型

信号量可以视为是一个更广义的锁!!

锁就是一个特殊的信号量(可用资源只有一个 1 的信号量)

把互斥锁也看作是计数为1的信号量(取值只有1和0,也叫做二元信号量)

JAVA标准库提供了Semaphore这个类,其实就是把 操作系统 提供的信号量封装了一下

信号量互斥例子:

在这里插入图片描述
可以看到,只打印了4个P操作,因为可用资源已经没有了,所以在第五个acquire()处就会发生阻塞,这个阻塞就会一直阻塞,直到其他线程进行释放

当需求中,有多个可用资源的时候,就记得要使用信号量~

P 和 V 是荷兰语,P 和 V 是荷兰语中申请和释放的首字母~
在这里插入图片描述

6.CountDownLatch

类似于一个跑步比赛 ~
当最后一个选手到达终点,比赛就结束~

使用CountDownLatch 就是类似的效果
使用的时候先设置以下有几个选手~
每个选手撞线了,就调用一下countDown方法,当撞线的次数达到了选手的个数,就认为比赛结束了~

比如使用多线程完成一个任务~

例如,要下载一个很大的文件,就切分成多个部分,每个线程负责下载其中的一个部分~
当所有的线程都下载完毕,整个文件就下载完毕了~

import java.util.concurrent.CountDownLatch;


public class countdownlatch {

    public static void main(String[] args) throws InterruptedException {
        //有5份文件需要下载
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
            //创建5个线程来执行一批任务
            Thread thread = new Thread(()-> {
                System.out.println("开始执行任务" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("结束执行任务" + Thread.currentThread().getName());
                //记录完成
                countDownLatch.countDown();
            });
            thread.start();
        }

        //await进行阻塞等待,会等到所有的文件都下载完毕之后,才解除阻塞
        countDownLatch.await();
        System.out.println("文件下载完成!");
    }
}

再举个例子:

在这里插入图片描述

比如有一个服务挂了,那么响应回不来了怎么办?
await操作,是可以指定超时时间
可以加个参数:在这里插入图片描述

如果时间到了还没有收到相应,那就不等了~

总结

在这里插入图片描述

你可以叫我哒哒呀
本篇到此结束
“莫愁千里路,自有到来风。”
我们顶峰相见!

相关文章:

  • 【C++入门到实战,看这篇博客总结足够了】
  • 核酸检测多少人为一组混检合适?
  • JavaWeb学习之BS/CS架构及tomcat容器项目部署
  • Python入门必会技巧:pycharm配置Python解释器【2022最新】
  • Zookeeper集群搭建(Linux环境)
  • 今天面试被问到的问题
  • 【JAVAEE框架】SpringMVC 项目起步讲解
  • 【牛客-算法】NC57 反转数字
  • 福昕电子签章服务正式上线:文档签,击穿第三方信息屏障
  • 智能座舱指数首发!入榜「TOP10自主品牌OEM」都有谁
  • STM32F103移植FreeRTOS必须搞明白的系列知识---3(堆栈)
  • poi数据获取、学校poi分布、医院poi分布、公园分布、地铁分布、道路网
  • 【微服务】一篇文章带你打开微服务大门
  • 今年快30岁的我,还是选择了裸辞···
  • 数据导入与预处理-第6章-01数据清理
  • JavaScript-如何实现克隆(clone)函数
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • C++类中的特殊成员函数
  • extjs4学习之配置
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Java应用性能调优
  • REST架构的思考
  • SQL 难点解决:记录的引用
  • Vim 折腾记
  • 大整数乘法-表格法
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 开源SQL-on-Hadoop系统一览
  • 少走弯路,给Java 1~5 年程序员的建议
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 探索 JS 中的模块化
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 温故知新之javascript面向对象
  • 线上 python http server profile 实践
  • 译有关态射的一切
  • Nginx实现动静分离
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​configparser --- 配置文件解析器​
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (07)Hive——窗口函数详解
  • (Forward) Music Player: From UI Proposal to Code
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (三)elasticsearch 源码之启动流程分析
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)jQuery 基础
  • (转)关于多人操作数据的处理策略
  • (转载)hibernate缓存
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)
  • ***原理与防范