JUC
其是单词缩写,全称是java.util.concurrent
concurrent的意思是并发,这个包放的都是多线程相关的
Callable接口
和Runnable接口类似,都是实现一个任务,不过Callable接口的任务带返回值
demo
public static void main(String[] args) throws Exception {
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();
System.out.println(futureTask.get());
}
我们的Thread类并不能直接传入Callable对象,而是要中间通过FutureTask进行转化,而且FutureTask也可以调用get方法得到Callable的返回值
ReentrantLock
是可重入锁
demo
public static void main(String[] args) {
ReentrantLock locker = new ReentrantLock(true);
try{
//locker.lock();
locker.tryLock();
} finally {
locker.unlock();
}
}
ReentrantLock的加锁和解锁过程是独立的,因此最好用try和finally包裹,否则这两者中间如果有return就会执行不到unlock
ReentrantLock还有tryLock方法,也就是尝试加锁,如果加锁失败了,就放弃加锁,也可以传入一个时间参数,如果加锁失败,就等一会,过了这个时间就放弃
在Reentrant构造方法中传入true,可以成为公平锁
ReentrantLock是搭配Condition类进行唤醒线程的,可以指定哪个线程唤醒
信号量
本身是一个计数器,统计可用资源的个数
信号量的基本操作有两个,P操作申请资源,可用资源就减一,V操作释放资源,可用资源就加一
锁是一个特殊的信号量,可用资源数只有一
semaphore
是java标准库中的类,将操作系统的信号量封装了起来
demo
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(4);
semaphore.acquire();//p操作
System.out.println("p");
semaphore.acquire();//p操作
System.out.println("p");
semaphore.acquire();//p操作
System.out.println("p");
semaphore.acquire();//p操作
System.out.println("p");
semaphore.acquire();//p操作
System.out.println("p");
semaphore.release();//v操作
}
用构造方法创建一个semaphore对象,传入的值就是总共有的信号量,调用acquire方法就相当于p操作,调用release方法就相当于v操作,当计数器的值变成0时,那么就会阻塞等待,直到别的线程调用release
CountDownLatch
用来统计分块执行的任务是否完成
相当于跑步比赛,每有一个人到终点就撞线一次,直到撞线的次数等于参加比赛的总人数,比赛就结束了。
实际应用场景:一个服务器负责多个服务器的数据的组织串联,使用CountDownLatch可以确认什么时候所有服务器的数据都传输完毕
demo
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
Thread t = 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();
});
t.start();
}
countDownLatch.await();
System.out.println("所有任务执行完毕");
}
在这个演示中,创建CountDownLatch统计十个线程分别完成任务,当一个线程执行完任务就调用countDown方法,然后调用await方法就可以使代码阻塞等待到所有线程都撞线完成,也就执行完所有的任务了