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

目录

Callable接口

ReentrantLock

[synchronized 和 ReentrantLock之间的区别](#synchronized 和 ReentrantLock之间的区别)

信号量Semaphore

CountDownLatch


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

Callable接口

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

Callable接口和Runnable接口并列关系

返回值call()

泛型参数
代码⽰例: 创建线程计算 1 + 2 + 3 + ... + 1000, 使⽤ Callable 版本

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Demo40 {
    public static void main(String[] args) {
        //此处Callable只是定义了一个"带有返回值"的任务
        //并没有真的在执行,执行还是需要搭配Thread对象
        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();
        System.out.println(futureTask.get());
    }
}

Thread的构造方法,没有提供版本传入Callable对象

Thread本身不提供获取结果的方法

就需要凭FutureTask对象来拿到结果
**代码⽰例: ** 创建线程计算 1 + 2 + 3 + ... + 1000, 不使⽤ Callable 版本

java 复制代码
public class Demo41 {
    private static  int total = 0;
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                int sum = 0;
                for (int i = 1; i <= 100; i++) {
                    sum += 0;
                }
                total = sum;
            }
        };
        Thread t =new Thread(runnable);
        t.start();
        t.join();
        System.out.println(total);
    }
}

理解 Callable
Callable 和 Runnable 相对, 都是描述⼀个 "任务". Callable 描述的是带有返回值的任务, Runnable
描述的是不带返回值的任务.
Callable 通常需要搭配 FutureTask 来使⽤. FutureTask ⽤来保存 Callable 的返回结果. 因为
Callable 往往是在另⼀个线程中执⾏的, 啥时候执⾏完并不确定.
FutureTask 就可以负责这个等待结果出来的⼯作.
理解 FutureTask
想象去吃⿇辣烫. 当餐点好后, 后厨就开始做了. 同时前台会给你⼀张 "⼩票" . 这个⼩票就是
FutureTask. 后⾯我们可以随时凭这张⼩票去查看⾃⼰的这份⿇辣烫做出来了没


ReentrantLock

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

和synchronized是并列关系

更经典风格的锁

java 复制代码
import java.util.concurrent.locks.ReentrantLock;

public class Demo42 {
    private static int count = 0;
    public static void main(String[] args) {
        ReentrantLock locker = new ReentrantLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5000; i++) {
                    locker.lock();
                    try{
                        count++;
                    }finally {
                        locker.unlock(); 
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5000; i++) {
                    locker.lock();
                    try{
                        count++;
                    }finally {
                        locker.unlock();
                    }
                }
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        
    }
}

synchronized 和 ReentrantLock之间的区别

1.synchronized 是关键字(内部实现是jvm内部通过c++实现的)ReentrantLock标准库的类(Java)

2.synchronized通过代码块控制加锁解锁,ReentrantLock需要lock/unlock方法,需要注意unlock不被调用的问题

3.ReentrantLock除了提供lock,unlock之外还提供了一个方法tryLock()

tryLock不会阻塞

加锁成功返回true,失败返回false

调用者判定返回值决定接下来咋做

设置超时时间

等待时间达到超时时间在返回true/false

4.ReentrantLock提供了公平锁的实现

java 复制代码
ReentrantLock locker = new ReentrantLock(true);

默认是非公平的

5.ReentrantLock搭配的等待通知机制是Condition类,相比wait,notify来说功能更强大一些


信号量Semaphore

信号量, ⽤来表⽰ "可⽤资源的个数". 本质上就是⼀个计数器

能够协调多个进程之间的资源分配

也能协调多个线程之间的资源分配

申请acquire一个资源,计数器就会-1,p操作

释放release一个资源,计数器就会+1,v操作

计数器为0,继续申请就会阻塞等待

java 复制代码
import java.util.concurrent.Semaphore;

public class Demo43 {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(4);
        semaphore.acquire();
        System.out.println("进行一次p操作");
        semaphore.acquire();
        System.out.println("进行一次p操作");
        semaphore.acquire();
        System.out.println("进行一次p操作");
        semaphore.acquire();
        System.out.println("进行一次p操作");
    }
}

信号量的一个特殊情况,初始值为1 的信号量

取值要么是1要么是0(二元信号量)

等价于"锁"(普通的信号量,就相当于锁的更广泛的推广)

如果是普通的N的信号量,就可以限制同时有多少个线程来执行某个逻辑

java 复制代码
import java.util.concurrent.Semaphore;

public class Demo44 {
    private static int count = 0;
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(1);
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5000; i++) {
                    try {
                        semaphore.acquire();
                        count++;
                        semaphore.release();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5000; i++) {
                    try {
                        semaphore.acquire();
                        count++;
                        semaphore.release();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        });
        t1.start();
        t2.start();
    }
}

CountDownLatch

同时等待N个任务执行结束

使用多线程经常把一个大的任务拆分成多个子任务

使用多线程执行这些子任务,从而提高程序的效率

1.构造方法指定参数,描述拆成了多少个任务

2.每个任务执行完毕之后,都调用一次countDown方法

如果指定10个任务,当一共调用了10次countDown说明任务全都完成了

3.主线程中调用await方法,等待所以任务执行完毕

await就会返回/阻塞等待

java 复制代码
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo45 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService executor = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 10; i++) {
            int id = i;
            executor.submit(()->{
                System.out.println("子任务开始执行"+id);
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e){
                    throw new RuntimeException(e);
                }
                System.out.println("子任务结束执行"+id);
            });

        }
        latch.await();//阻塞等待所有的任务结束
        System.out.println("所有任务执行完毕");
        executor.shutdown();
    }
}
相关推荐
2301_780789668 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
第九序言T8 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
学长毕设9 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn10 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川10 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵10 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
程序喵大人10 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
秋天的怀念_David10 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas10010 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin11 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php