Callable
官方文档:Callable接口类似于Runnable ,因为它们都是为其实例可能由另一个线程执行的类设计的。 然而, Runnable不返回结果,也不能抛出被检查的异常。
- 可以有返回值
- 可以抛出异常
- 方法不同,run() / call()
调用Callable
FutureTask futureTask = new FutureTask<>(c); //适配类
new Thread(futureTask,"A").start();
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//new Thread(new Runnable()).start();
//new Thread(new FutureTask<V>()).start();
//new Thread(new FutureTask<V>(Callable)).start();
new Thread().start(); //怎么启动callable
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask<>(myThread); //适配类
new Thread(futureTask,"A").start();
Object o = futureTask.get(); //获取Callable的返回结果,get方法可能会产生阻塞,一般放到最后,或者使用异步通信
System.out.println(o);
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("call()");
return "aaa";
}
}
问题:如果new两个线程会打印几个call()?
答案:一个
分析:结果会被缓存,效率高
常用的辅助类
1、CountDownLatch(减法计数器)
//计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//总数是6,必须要在执行任务的时候,再使用
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" go out");
countDownLatch.countDown(); //数量-1
},String.valueOf(i)).start();
}
countDownLatch.await(); //等待计数器归零,再向下执行
System.out.println("Close door");
}
6个线程都走完才会向下执行
countDownLatch.countDown(); // 数量-1
countDownLatch.await(); // 等待计数器归零,然后再向下执行
每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续执行!
如果 countDown()没有减到0,后面的程序是不会执行的
2、CylicBarrier(加法计数器)
public class CylicBarrierDemo {
public static void main(String[] args) throws InterruptedException {
//集齐7颗龙珠召唤神龙
//召唤龙珠的线程
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("召唤神龙成功");
});
for (int i = 1; i <= 7; i++) {
final int temp = i;
new Thread(()->{
//lambda表达式获取不到i
System.out.println(Thread.currentThread().getName()+"收集了"+temp+"颗龙珠");
try {
cyclicBarrier.await(); //等待
System.out.println(Thread.currentThread().getName()+"----------");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
cyclicBarrier.await(); //等待
每次运行到这里会进行等待,直到7个线程齐了才会继续执行下面的的代码
3、Semaphore(信号量)
//模拟停车,假设现在有6辆车,但是只有3个停车位
//在有限的情况下使其有秩序,限流的时候可以使用
public class SemaphoreDemo {
public static void main(String[] args) throws InterruptedException {
//线程数量:停车位
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
// acquire() 得到
// release() 释放
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到车位");
//停2s后离开
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // release() 释放
}
},String.valueOf(i)).start();
}
}
}
原理:
semaphore.acquire():获得,假设如果已经满了,等待,等到被释放为止!
semaphore.release():释放,会将当前的信号量释放 + 1,然后唤醒等待的线程!
作用: 多个共享资源互斥的使用!并发限流,控制最大的线程数!