职场面试题总结(12)---线程异步编排、Callable与Runnable、CountDownLatch和CyclicBarrier

227 阅读3分钟

1、线程异步编排

CompletableFuture 异步编排 业务场景:查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。 异步编排的好处:假如商品详情页的每个查询,需要如下标注的时间才能完成。那么,用户需要6.5s后才能看到商品详情页的内容。很显然是不能接受的。如果有多个线程同时完成这6步操作,也许只需要1.5s 即可完成响应。 在这里插入图片描述

2、Callable与Runnable

Runable与Callable相同点: (1)两者都是接口; (2)两者都可用来编写多线程程序; (3)两者都需要调用Thread.start()启动线程;

Runable与Callable不同点: (1)实现Callable接口的任务线程能返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取call()返回的结果;当不调用此方法时,主线程不会阻塞;而实现Runnable接口的任务线程不能返回结果; (2)Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

3、CountDownLatch和CyclicBarrier

CountDownLatch await():阻塞主线程,直到countDownLatch的计数器减少到0的位置。 countDown:将当前的计数器减1。 getCount:返回当前的数。

CyclicBarrier 每个线程中调用await,调用达到次数再一起放行。调用栅栏(计数器为5)的await,相当于告诉栅栏已经有一个线程到达栅栏,同时线程本身不再继续执行;当cyclicBarrier的await方法调用5次时,所有线程继续执行,同时触发栅栏的run方法

4、线程安全如何实现

(1)不适用单例模式,而是用多实例。 (2)使用锁机制Synchronized、lock方式。 (3)使用java.util.concurrent下面的类库。

5、Lock

Lock完全用Java写成,在java这个层面是无关JVM实现的。 在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock、ReadWriteLock(实现类ReentrantReadWriteLock),其实现都依赖java.util.concurrent.AbstractQueuedSynchronizer类。

Lock和synchronized的区别和选择 (1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现; (2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁; (3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断; (4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。 (5)Lock可以提高多个线程进行读操作的效率。 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。在具体使用时要根据适当情况选择使用synchronized还是Lock。