Top 50 Java 线程并发的面试问题
2015-11-15 14:11
756 查看
问题1 什么是executor框架
Executor and ExecutorService用于以下场景:- 创建线程
- 启动线程
- 管理整个线程的生命周期
Executor创建线程池并管理线程池中线程的生命周期,在executor框架中,Executor接口和ExecutorService接口被频繁使用。Executor接口定义了execute()方法用于执行命令。ExecutorService接口继承Executor。
Executor提供了管理终止或产生Future追踪过程或异步任务的方法,更多内容请阅读Executor and ExecutorService framework in java。
问题2 executor框架中execute()和submit()的区别
execute()方法 | submit()方法 |
---|---|
execute()方法定义在Executor接口中 | submit()方法定义在ExecutorService接口中 |
用于执行runnable任务 | 用于执行runnable任务或callable任务,提交callable任务返回future对象,通过future.get()获取任务的结果 |
方法类型只有一种void execute(Runnable task) | submit方法有3种形式:<T> Future<T> submit(Callable<T> task) <T> Future<T> submit(Runnable task, T result) Future<?> submit(Runnable task) |
问题3 什么是Semaphore?
Semaphore通过许可控制共享资源的访问:- 如果许可permits大于0,semaphore允许访问共享资源;
- 如果许可permits小等于0,semaphore不允许访问共享资源;
其中许可有点类似计数器,用来允许访问共享资源,为此,为了访问该资源,线程必须从semaphore那里授权许可。
Semaphore有两个构造函数:
1.
Semaphore(int permits):permits是初始的可用许可,这个值有可能是负值,表示此刻等待获取共享资源的线程数。如果permits=1,表示只有一个线程正在使用共享资源。
2.
Semaphore(int permits, boolean fair):设置fair,能确保等待线程按请求顺序被授权。
acquire( )方法有两种形式:
1.
void acquire( ) throws InterruptedException:获取一个可用许可,并且可用许可减1。
2.
void acquire(int permits) throws InterruptedException:获取permits个可用许可,同时可用许可减permits。如果permits个许可不可用,那么当前线程处于休眠状态,直到发生如下事情:
- 其他线程调用
release()方法,可用许可大等于permits;
- 或者其他线程中断该线程。
release( )方法有两种形式:
1.
void release( ):释放许可,并且许可加1。
2.
void release(int permits):释放permits个许可,并且可用许可增加permits个。
有关Semaphor请阅读Semaphore in java。
问题4 利用Semaphore实现生产者消费者模式
请阅读:Semaphore used for implementing Producer Consumer pattern问题5 实现自己的Semaphore
请阅读:Implementation of custom/own Semaphore in java问题6 Java 7中atomic类的意义
Java在java.util.concurrent.atomic中提供了其他的同步类,这些类有AtomicInteger、
AtomicLong、
AtomicBoolean等,相应的方法有
get(),
set(),
getAndSet(),
compareAndSet( ),
decrementAndGet( )等。在多线程环境下,这些类不需要显示地进行同步,因为它们是线程安全的。
atomic的更多内容请参考Atomic operations in java。
问题7 Future和Callable之间的关联?
Future<V>接口提供的方法用于返回计算的结果,计算未完成会一直等待,或者取消计算任务。
Callable<V>接口提供了计算结果的方法,并返回计算结果,或者抛出异常。任何实现Callable接口的类必须重写call()方法。
向Executor提交Callable对象返回的对象类型是Future,如:
Future<Double> futureDouble=executor.submit(new SquareDoubleCallable(2.2));
更多内容请阅读Executor and ExecutorService framework in java。
问题8 java.util.concurrent.Callable和java.lang.Runnable不同?
实现Callable接口的类必须重写call()方法,call()方法返回计算结果或者无法执行抛出异常;实现Runnable接口的类必须重写run()方法,run()方法不会返回计算结果,也不抛出检查异常。
问题9 CountDownLatch
CountDownLatch适用于当前线程等待一个或多个线程完成特定的操作。CountDownLatch(int count) 初始化需要确定在latch释放之前发生事件的个数。事件每次发生count减1,一旦count减为0,latch被释放。CountDownLatch的await()方法有两种形式:
- void await( ) throws InterruptedException
引起当前线程等待,直到latch count减为0,或者当前线程被中断。
- boolean await(long timeout, TimeUnit unit)
引起当前线程等待,直到latch count减为0,或者当前线程被中断,或者超时。
countDown()方法用来减少latch count计数。count减为0,所有等待线程被释放。
了解更多请阅读CountDownLatch in java。
问题10 CountDownLatch的使用场景
请阅读CountDownLatch in java。问题11 如何实现CountDownLatch?
请阅读Implementation of custom/own CountDownLatch in java。问题12 CyclicBarrier
CyclicBarrier用于一个或多个线程完成都完成特定的操作才触发一个事件。2个或者多个线程彼此等待直到到达共同的barrier point。当所有的线程到达共同的barrier point(即所有的线程调用await()方法):- 所有的等待线程被释放;
- 事件被触发。
CyclicBarrier的构造函数:
- CyclicBarrier(int parties)
新的CyclicBarrier被创建,当parties个等待线程到达共同的barrier point,等待的线程被释放。
- CyclicBarrier(int parties, Runnable barrierAction)
新的CyclicBarrier被创建,当parties个等待线程到达共同的barrier point,等待的线程被释放,barrierAction事件被触发。
CyclicBarrier的await()方法:
- int await() throws InterruptedException, BrokenBarrierException
- int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
当前的线程如果不是最后到达的(即调用await()方法),它会等待直到发生如下事情:
1. 最后一个线程调用await()方法
2. 其他线程中断了当前线程
3. 其他线程中断了其中的一个等待线程
4. 等待barrier的过程中一些线程超时
5. 在这个cyclicBarrier上的线程调用了reset()方法
6. 经过了timeout时间
更多内容请阅读CyclicBarrier in java。
问题13 为什么CyclicBarrier能够循环?
barrier之所以能够循环,是因为CyclicBarrier能够重用,当所有的等待线程释放,或者事件已被触发。问题14 在实际场景中什么时候使用CyclicBarrier?
举例:有10个好朋友打算去地点A野餐(朋友是线程,地点A是共同的barrier point),他们决定玩某个游戏当所有的人员到达地点A(游戏是一个事件)。所以10个朋友必须等到他们都到齐才能进行游戏。问题15 如何实现CyclicBarrier?
请参考Implementation of custom/own CyclicBarrier in java。问题16 CyclicBarrier和CountDownLatch之间的异同
CyclicBarrier和CountDownLatch有点相似,是因为它们要等待特定数量的线程到达某个点,然后使count或者parties等于0。但是CountDownLatch完成等待,线程必须调用countDown()方法;而CyclicBarrier完成等待,线程必须调用await()方法。它们的构造函数区别:
CountDownLatch(int count) :count确定latch释放之前发生的事件个数;
CyclicBarrier(int parties):parties个线程相互等待到达共同的barrier point,当所有的线程到达这个共同的barrier point,parties个等待线程被释放。
CyclicBarrier可以重复等待,而CountDownLatch不能,即一旦count减为0,cyclicBarrier可重复使用。
CyclicBarrier可以触发事件。
问题17 Phaser是什么?
Phaser在功能上和CyclicBarrier和CountDownLatch有点相似,但是比它俩更加灵活。Phaser为我们提供了更加灵活的注册和取消注册。对于注册,可以使用下面的方式:
- 构造函数
- int register()
- bulkRegister()
对于取消注册,可以使用下面的方式:
- arriveAndDeregister()
可以使用getPhase()方法返回当前的phase个数,isTerminated()返回phaser时候结束。
更多内容请阅读Phaser in java。
问题18 Phaser和CyclicBarrier之间的异同
CyclicBarrier和Phaser都可以重复等待。在CyclicBarrier中,在构造函数中注册,但是Phaser提供了在任何时候注册和取消注册的方法。问题19 Phaser的arrive()方法和arriveAndAwaitAdvance() 的区别
Phaser的arrive()方法不会引起当前线程等待其他线程完成当前的phase,即当前线程可以立刻进入下一个phase,无须等待其他注册线程完成当前的phase。而arriveAndAwaitAdvance()方法会让当前线程去等待其他注册线程完成当前的phase,即只有当其他的所有线程完成当前的phase,当前线程才可以进行下一个phase。
问题20 phaser什么时候结束
调用Phaser的arriveAndDeregister() 方法会让注册的线程数变为0。当onAdvance()方法返回true,终止也会被触发。问题21 如何控制phase的个数
请参考:Program to demonstrate usage of how we can override Phaser’s onAdvance method to control number of phase we want to execute。问题22 Phaser的使用场景
软件开发管理按如下phase进行:1. 需求收集;
2. 软件开发;
3. 测试;
第二个phase不会开始直到第一个phase完成,第三个phase也不会开始直到第二个phase完成。
问题23 每次phaser注册的最大数量
每次phaser注册的数量为65535,如果想注册更多的线程,将会抛出IllegalStateException。问题24 Exchanger
Exchanger能够使两个线程交换彼此的数据,它能够非常容易地实现生产者消费者模式,生产者和消费者线程交换彼此的数据。exchange(V x)方法能够使两个线程交换彼此的数据,如果当前线程是第一个调用exchange()方法,那它会等待直到其他线程调用exchange()方法,或者其他线程中断当前线程。如果其他线程已经调用了exchange()方法,那么它会恢复执行,等待线程恢复并接受当前线程的数据,或者当前线程收到其他等待线程的数据,立刻返回。
更多内容请阅读Exchanger in java。
问题25 用Exchanger实现生产者消费者模式
请参考Read program to implement Producer Consumer pattern using Exchanger。问题26 使用BlockingQueue解决生产者消费者模式
请参考BlockingQueue is a interface and we will use its implementation class LinkedBlockingQueue。问题27 使用BlockingQueue解决生产者消费者模式
请参考Producer Consumer pattern using Custom implementation of LinkedBlockingQueue interface。问题28 java Lock
java.util.concurrent.locks.Locks是一个接口,它的实现类提供了更实用的锁操作。lcok有助于控制多线程共享资源的访问,每次只有一个线程获取锁,并且访问共享资源。如果第二个线程试图访问锁上的共享资源,当这个锁被另一个线程获取,那么第二个线程处于等待,直到锁被释放。这样就可以实现同步和避免竞争。更多内容请阅读locks and ReEntrantLocks in java。
问题29 Lcok 接口中的关键方法
void lock()
如果锁没有被其他线程占用,获取锁。设置锁计数为1;如果当前线程已经占用了锁,那么说计数器加1;如果锁被其他线程占用,那么当前线程等待直到锁被释放。
void unLock()
如果当前线程占用了锁,那么锁计数器减1;如果锁计数器减为0,那么锁被释放;如果锁计数器大于0,那么锁没有被释放;如果当前线程没占用锁,那么抛出IllegalMonitorStateException异常。
boolean tryLock()
获取锁如果没有被其他线程占用,并返回true,设置锁计数器设置为1。如果当前线程已经占有了锁,那么返回true,并锁计数器加1.如果锁被其他线程占用,返回false。
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
获取锁如果没有被其他线程占用,返回true,设置锁计数器为1。如果当前线程已经占有了锁,返回true,并且锁计数器加1。如果锁被其他线程占用,那么当前线程等待直到发生如下:1、另一个线程释放锁,当前线程获取锁;2、其他线程中断了当前线程;3、设定的时间超时。
Condition newCondition()
返回Condition实例,被用于锁接口。Condition实例类似于wait(), notify(), notifyAll()方法。
更多请阅读locks in java。
原文:Thread concurrency - Top 50 interview questions and answer in java for fresher and experienced (detailed explanation with programs)
相关文章推荐
- Java再学习——随机面试题
- 一道js面试题引发的思考
- 找出一个整数数组中,第二大的数
- 四到五年的程序员怎么突破?
- 看见的一个mysql面试题
- 黑马程序员_NSArray
- .net面试问答(大汇总)
- 面试题一
- 老程序员给初学者的一些建议和忠告
- J2EE面试题
- 黑马程序员——File类及Properties类
- 黑马程序员——常用类
- concat、reverse面试题
- Switch中的参数
- Java面试宝典-assert
- 如何做一个开心的程序员
- [No000048]程序员的成长过程中,有哪些阶段?
- 程序员编程艺术第二章
- 程序员编程艺术第一章(第二节)
- 80后的程序员,你们存了多少钱,买房还差多少?