您的位置:首页 > 职场人生

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之间的异同

CyclicBarrierCountDownLatch有点相似,是因为它们要等待特定数量的线程到达某个点,然后使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在功能上和CyclicBarrierCountDownLatch有点相似,但是比它俩更加灵活。

Phaser为我们提供了更加灵活的注册和取消注册。对于注册,可以使用下面的方式:

- 构造函数

- int register()

- bulkRegister()

对于取消注册,可以使用下面的方式:

- arriveAndDeregister()

可以使用getPhase()方法返回当前的phase个数,isTerminated()返回phaser时候结束。

更多内容请阅读Phaser in java

问题18 Phaser和CyclicBarrier之间的异同

CyclicBarrierPhaser都可以重复等待。在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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: