文章目录
Callable接口
1.继承了Thread(包含了匿名内部类的方法)
2.实现了Runnable(包含了匿名内部类的方式)
3.基于lambda
4.基于线程池
Runnable与Callable的区别:
Runnable关注的是这个过程,不关注执行结果
Runnable提供的run方法,返回值类型是void
Callable关注过程,也关注结果
Callab提供的call方法,返回值就是线程执行任务得到的结果
举例说明:
创建一个新线程,用新线程实现1+2+3+4+...+1000;
使用Thread写的代码:
java
public class Test16 {
public static int sum = 0;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
int result = 0;
for (int i = 1; i <= 1000; i++) {
result+=i;
}
sum = result;
}
});
t.start();
t.join();
System.out.println("sum=" + sum);
}
}
这样写的代码不美观,且如果有多个线程就要创建多个成员变量来接收result。
使用Callable写的代码:
java
public class Test17 {
public static void main(String[] args) throws ExecutionException,InterruptedException {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int result = 0;
for (int i = 1; i <= 1000 ; i++) {
result+=i;
}
return result;
}
};
FutureTask<Integer> task = new FutureTask<>(callable);
Thread t = new Thread(task);
t.start();
System.out.println(task.get());
}
代码解释:
创建⼀个匿名内部类, 实现 Callable 接⼝. Callable 带有泛型参数. 泛型参数表⽰返回值的类型.
• 重写 Callable 的 call ⽅法, 完成累加的过程. 直接通过返回值返回计算结果.
• 把 callable 实例使⽤ FutureTask 包装⼀下.
• 创建线程, 线程的构造⽅法传⼊ FutureTask . 此时新线程就会执⾏ FutureTask 内部的 Callable 的call ⽅法, 完成计算. 计算结果就放到了FutureTask 对象中.
• 在主线程中调⽤ futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结果。
FutureTask类,作为Thread和callable的粘合剂
理解 Callable
Callable 和 Runnable 相对, 都是描述⼀个 "任务". Callable 描述的是带有返回值的任务, Runnable描述的是不带返回值的任务.
Callable 通常需要搭配 FutureTask 来使⽤. FutureTask ⽤来保存 Callable 的返回结果. 因为Callable 往往是在另⼀个线程中执⾏的, 啥时候执⾏完并不确定.
FutureTask 就可以负责这个等待结果出来的⼯作.
理解 FutureTask
想象去吃⿇辣烫. 当餐点好后, 后厨就开始做了. 同时前台会给你⼀张 "⼩票" . 这个⼩票就是FutureTask. 后⾯我们可以随时凭这张⼩票去查看⾃⼰的这份⿇辣烫做出来了没.
ReentrantLock
可重入互斥锁,和synchronized定位类似,都是来实现互斥效果,保证线程安全
ReentrantLock也是可重入锁,
ReentrantLock的用法:
lock( ) : 加锁,如果获取不到锁就死等
trylock(超时间):加锁,如果获取不到锁,等待一段时间之后就放弃加锁
unlock():解锁
java
ReentrantLock lock = new ReentrantLock();
-----------------------------------------
lock.lock();
try {
// working
} finally {
lock.unlock()
}
ReentrantLock和synchronized的区别
1.ReentrantLock提供了tryLock操作
2.ReentrantLock提供了公平锁的实现
synchronized是非公平锁
ReentrantLock构造方法中填写参数,就可以设置成公平锁
3.搭配的等待通知机制不同的
对于synchronized搭配wait/notify
对于ReentrantLock搭配Condition类,功能比wait notify略强一点
信号量Semaphore
信号量,用来表示"可用资源的个数",本质上就是一个计时器
如何理解信号量
可以把信号量想象成是停⻋场的展⽰牌: 当前有⻋位 100 个. 表⽰有 100 个可⽤资源.
当有⻋开进去的时候, 就相当于申请⼀个可⽤资源, 可⽤⻋位就 -1 (这个称为信号量的 P 操作)
当有⻋开出来的时候, 就相当于释放⼀个可⽤资源, 可⽤⻋位就 +1 (这个称为信号量的 V 操作)
如果计数器的值已经为 0 了, 还尝试申请资源, 就会阻塞等待, 直到有其他线程释放资源.
Semaphore 的 PV 操作中的加减计数器操作都是原⼦的, 可以在多线程环境下直接使⽤.
代码示例
• 创建 Semaphore ⽰例, 初始化为 4, 表⽰有 4 个可⽤资源.
• acquire ⽅法表⽰申请资源(P操作), release ⽅法表⽰释放资源(V操作)
• 创建 20 个线程, 每个线程都尝试申请资源, sleep 1秒之后, 释放资源. 观察程序的执⾏效果.
java
public class Test18 {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(4);
Runnable runnable = 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) {
throw new RuntimeException(e);
}
}
};
for (int i = 0; i < 20; i++) {
Thread t = new Thread(runnable);
t.start();
}
}
}
CountDownLatch
同时等待 N 个任务执⾏结束.
好像跑步⽐赛,10个选⼿依次就位,哨声响才同时出发;所有选⼿都通过终点,才能公布成绩。
• 构造 CountDownLatch 实例, 初始化 10 表⽰有 10 个任务需要完成.
• 每个任务执⾏完毕, 都调⽤ latch.countDown() . 在 CountDownLatch 内部的计数器同时⾃
减.
• 主线程中使⽤ latch.await(); 阻塞等待所有任务执⾏完毕. 相当于计数器为 0 了.
java
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class Test19 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(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;
System.out.println("线程"+id+"开始下载");
try {
Thread.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程"+id+"下载完成");
countDownLatch.countDown();
});
t.start();
}
countDownLatch.await();
System.out.println("全部下载完成");
}
}