1 Callable接口
Runnable接口和Callable接口都可以用于创建线程,但二者有功能上的差异
1,Runnable接口无返回值,Callable接口有返回值
2,Runnable接口无法抛异常,Callable接口可以抛异常
使用Callable接口创建线程可以使用FutureTask
FutureTask用于计算"未来任务" 不影响主线程的情况下开启一个线程计算结果
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask1 = new FutureTask(new Callable() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " call");
return 100;
}
});
Thread a = new Thread(futureTask1, "a");
a.start();
while (!futureTask1.isDone()) {
System.out.println("wait");
}
System.out.println(futureTask1.get());
System.out.println(futureTask1.get());
}
2 JUC中的辅助类
2.1 CountDownLatch 减少计数
CountDownLatch类可以设置一个计数器 然后通过countDown()方法来执行减1的操作
CountDownLatch主要有两个方法 当一个或多个线程调用await()时 这些线程会阻塞
其它线程调用countDown()时会将计数器减1 调用countDown()方法的线程不会阻塞
当计数器的值为0时 因await()阻塞的线程会被唤醒 继续执行
使用场景如: 教室离开6个同学后再锁门
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 同学离开");
countDownLatch.countDown();
}
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " 6个同学离开后,锁门");
}
2.2 CyclicBarrier 循环栅栏
CyclicBarrier循环阻塞 其构造需要的参数即"目标障碍数"和"目标任务"
每执行一次await()一次 障碍数加1
如果达到了目标障碍数 才会执行目标任务
没有达到目标障碍数则会一直等待
使用场景如: 凑够5个人一起玩游戏
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("凑够5人一起玩游戏");
}
});
for (int i = 1; i <= 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 号报到");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}, String.valueOf(i)).start();
}
}
2.3 Semaphore 信号灯
Semaphore构造的第一个参数是"最大信号量" 第二个是"公平/非公平" 默认非公平
每个信号量可以看作一个"许可证" 拿到许可的线程才能执行
使用acquire()可以获取许可 通过release()释放许可
使用场景如: 6辆车抢3个车位
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 抢到了车位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + " 离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}, String.valueOf(i)).start();
}
}