多线程进阶-JUC

65 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天

7.Callable(简单)

image-20221008105749262

  1. 可以有返回值
  2. 可以抛出异常
  3. 方法不同,run()/call()

代码测试

image-20221008115433885

 public class CallableTest {
     public static void main(String[] args) throws ExecutionException, InterruptedException {
         new Thread().start();
 ​
         MyThread thread = new MyThread();
         FutureTask futureTask = new FutureTask(thread);//适配器
 ​
         new Thread(futureTask,"A").start();
         new Thread(futureTask,"B").start(); //结果会被缓存
 ​
         Integer o  = (Integer) futureTask.get();//获取callable的返回结果
         System.out.println(o);
 ​
 ​
     }
 }
 ​
 ​
 class MyThread implements Callable<Integer> {
 ​
 ​
     @Override
     public Integer call() throws Exception {
         System.out.println("call()");
         return 1024;
     }
 }

细节:

  1. 有缓存
  2. 结果可能需要等待,会阻塞

8.常用的辅助类(必须学会)

8.1 CountDownLatch

image-20221008163108927

 //计数器
 public class CountDownLatchDemo {
     public static void main(String[] args) throws InterruptedException {
         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");
 ​
     }
 }
 ​

原理:

countDownLatch.countDown(); // 数量-1

countDownLatch.await();//等待计数器归零

每次有线程调用countDown()数量-1 , 假设计数器变为0 , countDownLatch就会被唤醒,继续执行。

其实就是一个减法计数器,对于计数器归零之后再进行后面的操作,这是一个计数器!

8.2 CyclicBarrier

image-20221008163157164

其实就是一个加法计数器;

 public class CyclickBarrierDemo {
     public static void main(String[] args) {
         //集齐7颗龙珠召唤神龙
         CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
             System.out.println("召唤神龙成功");
         });
 ​
         //召唤龙珠的过程
         for (int i = 1; i <= 7; i++) {
             final int temp = i;
             new Thread(()->{
                 System.out.println(Thread.currentThread().getName()+"收集了"+ temp + "个龙珠");
 ​
                 try {
                     cyclicBarrier.await();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (BrokenBarrierException e) {
                     e.printStackTrace();
                 }
             }).start();
         }
 ​
 ​
     }
 }
 ​

8.3 Semaphore

Semaphore:信号量

抢车位:

3个车位 6辆车:

 public class SemaphoreDemo {
     public static void main(String[] args) {
         //线程数量,停车位
         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()+ "抢到车位");
                     TimeUnit.SECONDS.sleep(2);
                     System.out.println(Thread.currentThread().getName()+"离开车位");
 ​
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }finally {
                     semaphore.release();
                 }
 ​
 ​
             },String.valueOf(i)).start();
         }
     }
 }
 ​

原理:

semaphore.acquire()获得资源,如果资源已经使用完了,就等待资源释放后再进行使用!

semaphore.release()释放,会将当前的信号量释放+1,然后唤醒等待的线程!

作用: 多个共享资源互斥的使用! 并发限流,控制最大的线程数!