Java多线程常用面试题(含答案,精心总结整理)

Java并发编程问题是面试过程中很容易遇到的问题,提前准备是解决问题的最好办法,将试题总结起来,时常查看会有奇效。

现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。

核心:

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。 
比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。 
想要更深入了解,建议看一下join的源码,也很简单的,使用wait方法实现的。

t.join(); //调用join方法,等待线程t执行完毕 
t.join(1000); //等待 t 线程,等待时间是1000毫秒。

代码实现:


    
    
  1. public static void main (String[] args) {
  2. method01();
  3. method02();
  4. }
  5. /**
  6. * 第一种实现方式,顺序写死在线程代码的内部了,有时候不方便
  7. */
  8. private static void method01 () {
  9. Thread t1 = new Thread( new Runnable() {
  10. @Override public void run () {
  11. System.out.println( ”t1 is finished”);
  12. }
  13. });
  14. Thread t2 = new Thread( new Runnable() {
  15. @Override public void run () {
  16. try {
  17. t1.join();
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. System.out.println( ”t2 is finished”);
  22. }
  23. });
  24. Thread t3 = new Thread( new Runnable() {
  25. @Override public void run () {
  26. try {
  27. t2.join();
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. System.out.println( ”t3 is finished”);
  32. }
  33. });
  34. t3.start();
  35. t2.start();
  36. t1.start();
  37. }
  38. /**
  39. * 第二种实现方式,线程执行顺序可以在方法中调换
  40. */
  41. private static void method02 (){
  42. Runnable runnable = new Runnable() {
  43. @Override public void run () {
  44. System.out.println(Thread.currentThread().getName() + ”执行完成”);
  45. }
  46. };
  47. Thread t1 = new Thread(runnable, ”t1”);
  48. Thread t2 = new Thread(runnable, ”t2”);
  49. Thread t3 = new Thread(runnable, ”t3”);
  50. try {
  51. t1.start();
  52. t1.join();
  53. t2.start();
  54. t2.join();
  55. t3.start();
  56. t3.join();
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?

这个题的原答案我认为不是很全面。 
Lock接口 和 ReadWriteLock接口 如下:


    
    
  1. public interface Lock {
  2. void lock();
  3. void lockInterruptibly() throws InterruptedException;
  4. boolean tryLock();
  5. boolean tryLock( long time, TimeUnit unit) throws InterruptedException;
  6. void unlock();
  7. Condition newCondition();
  8. }
  9. public interface ReadWriteLock {
  10. Lock readLock();
  11. Lock writeLock();
  12. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

整体上来说Lock是synchronized的扩展版,Lock提供了无条件的、可轮询的(tryLock方法)、定时的(tryLock带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition方法)锁操作。另外Lock的实现类基本都支持非公平锁(默认)和公平锁,synchronized只支持非公平锁,当然,在大部分情况下,非公平锁是高效的选择。

ReadWriteLock是对Lock的运用,具体的实现类是 ReentrantReadWriteLock ,下面用这个类来实现读写类型的高效缓存:


    
    
  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import java.util.Random;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.locks.Lock;
  7. import java.util.concurrent.locks.ReadWriteLock;
  8. import java.util.concurrent.locks.ReentrantReadWriteLock;
  9. /**
  10. * 用ReadWriteLock读写锁来实现一个高效的Map缓存
  11. * Created by LEO on 2017/10/30.
  12. */
  13. public class ReaderAndWriter<K, V> {
  14. private final ReadWriteLock lock = new ReentrantReadWriteLock();
  15. private final Lock readLock = lock.readLock();
  16. private final Lock writeLock = lock.writeLock();
  17. private final Map< K, V> map;
  18. public ReaderAndWriter( Map< K, V> map) {
  19. this. map = map;
  20. }
  21. /************* 这是用lock()方法写的 ********************/
  22. // public V put(K key, V value){
  23. // writeLock.lock();
  24. // try {
  25. // return map.put(key, value);
  26. // }finally {
  27. // writeLock.unlock();
  28. // }
  29. // }
  30. // public V get(K key){
  31. // readLock.lock();
  32. // try {
  33. // return map.get(key);
  34. // }finally {
  35. // readLock.unlock();
  36. // }
  37. // }
  38. /************* 这是用tryLock()方法写的 ********************/
  39. public V put( K key, V value){
  40. while ( true){
  41. if(writeLock.tryLock()){
  42. try {
  43. System.out. println( "put "+ key + " = " + value);
  44. return map.put(key, value);
  45. } finally {
  46. writeLock.unlock();
  47. }
  48. }
  49. }
  50. }
  51. public V get( K key){
  52. while ( true){
  53. if (readLock.tryLock()) {
  54. try {
  55. V v = map. get(key);
  56. System.out. println( "get "+ key + " = " + v);
  57. return v;
  58. } finally {
  59. readLock.unlock();
  60. }
  61. }
  62. }
  63. }
  64. /******************** 下面是测试区 *********************************/
  65. public static void main( String[] args) {
  66. final ReaderAndWriter< String, Integer> rw = new ReaderAndWriter<>( new HashMap<>());
  67. ExecutorService exec = Executors.newCachedThreadPool();
  68. for (int i = 0; i < 100; i++) {
  69. exec.execute( new TestRunnable(rw));
  70. }
  71. exec.shutdown();
  72. }
  73. static class TestRunnable implements Runnable{
  74. private final ReaderAndWriter< String, Integer> rw;
  75. private final String KEY = "x";
  76. TestRunnable( ReaderAndWriter< String, Integer> rw) {
  77. this.rw = rw;
  78. }
  79. @Override
  80. public void run() {
  81. Random random = new Random();
  82. int r = random.nextInt( 100);
  83. //生成随机数,小于30的写入缓存,大于等于30则读取数字
  84. if (r < 30){
  85. rw.put( KEY, r);
  86. } else {
  87. rw. get( KEY);
  88. }
  89. }
  90. }
  91. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

在java中wait和sleep方法的不同?

通常会在电话面试中经常被问到的Java线程面试问题。 
最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

此处我想理一下Java多线程的基础知识: 
- Java的多线程锁是挂在对象上的,并不是在方法上的。即每个对象都有一个锁,当遇到类似synchronized的同步需要时,就会监视(monitor)每个想使用本对象的线程按照一定的规则来访问,规则也就是在同一时间内只能有一个线程能访问此对象。 
- Java中获取锁的单位是线程。当线程A获取了对象B的锁,也就是对象B的持有标记上写的是线程A的唯一标识,在需要同步的情况下的话,只有线程A能访问对象B。 
- Thread常用方法有:start/stop/yield/sleep/interrupt/join等,他们是线程级别的方法,所以并不会太关心锁的具体逻辑。 
- Object的线程有关方法是:wait/wait(事件参数)/notify/notifyAll,他们是对象的方法,所以使用的时候就有点憋屈了,必须当前线程获取了本对象的锁才能使用,否则会报异常。但他们能更细粒度的控制锁,可以释放锁。

用Java实现阻塞队列。

这是一个相对艰难的多线程面试问题,它能达到很多的目的。第一,它可以检测侯选者是否能实际的用Java线程写程序;第二,可以检测侯选者对并发场景的理解,并且你可以根据这个问很多问题。如果他用wait()和notify()方法来实现阻塞队列,你可以要求他用最新的Java 5中的并发类来再写一次。

下面是实现了阻塞的take和put方法的阻塞队列(分别用synchronized 和 wait/notify 实现):


    
    
  1. import java.util.LinkedList;
  2. import java.util.List;
  3. import java.util.Random;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. /**
  7. * 实现了阻塞的take和put方法的阻塞队列
  8. * 分别用synchronized 和 wait/notify 实现
  9. * @author xuexiaolei
  10. * @version 2017年11月01日
  11. */
  12. public class MyBlocingQueue< E> {
  13. private final List list;
  14. private final int limit; //有大小限制的
  15. public MyBlocingQueue ( int limit) {
  16. this.limit = limit;
  17. this.list = new LinkedList<E>();
  18. }
  19. //这是用synchronized写的,在list空或者满的时候效率会低,因为会一直轮询
  20. // public void put(E e){
  21. // while(true){
  22. // synchronized (list){
  23. // if (list.size() < limit) {
  24. // System.out.println("list : " + list.toString());
  25. // System.out.println("put : " + e);
  26. // list.add(e);
  27. // return;
  28. // }
  29. // }
  30. // }
  31. // }
  32. // public E take(){
  33. // while (true) {
  34. // synchronized (list) {
  35. // if (list.size() > 0){
  36. // System.out.println("list : " + list.toString());
  37. // E remove = (E) list.remove(0);
  38. // System.out.println("take : " + remove);
  39. // return remove;
  40. // }
  41. // }
  42. // }
  43. // }
  44. //用wait,notify写的,在list空或者满的时候效率会高一点,因为wait释放锁,然后等待唤醒
  45. public synchronized void put (E e){
  46. while (list.size() == limit){
  47. try {
  48. wait();
  49. } catch (InterruptedException e1) {
  50. e1.printStackTrace();
  51. }
  52. }
  53. System. out.println( "list : " + list.toString());
  54. System. out.println( "put : " + e);
  55. list. add(e);
  56. notifyAll();
  57. }
  58. public synchronized E take () {
  59. while (list.size() == 0){
  60. try {
  61. wait();
  62. } catch (InterruptedException e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. System. out.println( "list : " + list.toString());
  67. E remove = (E) list. remove( 0);
  68. System. out.println( "take : " + remove);
  69. notifyAll();
  70. return remove;
  71. }
  72. /******************** 下面是测试区 *********************************/
  73. public static void main (String[] args) {
  74. final MyBlocingQueue<Integer> myBlocingQueue = new MyBlocingQueue( 10);
  75. ExecutorService exec = Executors.newCachedThreadPool();
  76. for ( int i = 0; i < 100; i++) {
  77. exec.execute( new TestRunnable(myBlocingQueue));
  78. }
  79. exec.shutdown();
  80. }
  81. static class TestRunnable implements Runnable{
  82. private final MyBlocingQueue<Integer> myBlocingQueue;
  83. TestRunnable(MyBlocingQueue<Integer> myBlocingQueue) {
  84. this.myBlocingQueue = myBlocingQueue;
  85. }
  86. @ Override
  87. public void run () {
  88. Random random = new Random();
  89. int r = random.nextInt( 100);
  90. //生成随机数,按照一定比率读取或者放入,可以更改!!!
  91. if (r < 30){
  92. myBlocingQueue.put(r);
  93. } else {
  94. myBlocingQueue.take();
  95. }
  96. }
  97. }
  98. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

BlockingQueue介绍:

Java5中提供了BlockingQueue的方法,并且有几个实现,在此介绍一下。

BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

Throws exception Special value Blocks Times out
add(e) offer(e) put(e) offer(Object, long, TimeUnit)
remove() poll() take() poll(long, TimeUnit)
element() peek()    

- Throws exception 抛异常:如果试图的操作无法立即执行,抛一个异常。 
- Special value 特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false) 
- Blocks 阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。 
- Times out 超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是true / false)。

BlockingQueue 的实现类 
ArrayBlockingQueue:ArrayBlockingQueue 是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注:因为它是基于数组实现的,也就具有数组的特性:一旦初始化,大小就无法修改)。 
DelayQueue:DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现 java.util.concurrent.Delayed 接口。 
LinkedBlockingQueue:LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。 
PriorityBlockingQueue:PriorityBlockingQueue 是一个无界的并发队列。它使用了和类 java.util.PriorityQueue 一样的排序规则。你无法向这个队列中插入 null 值。所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。 
SynchronousQueue:SynchronousQueue 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点。

BlocingQueue的实现大多是通过 lock锁的多条件(condition)阻塞控制,下面我们自己写一个简单版:


    
    
  1. import java.util.LinkedList;
  2. import java.util.List;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. /**
  7. * 模仿ArrayBlockingQueue实现阻塞队列
  8. * @author xuexiaolei
  9. * @version 2017年11月01日
  10. */
  11. public class MyBlocingQueue2< E> {
  12. private final List list;
  13. private final int limit; //有大小限制的
  14. private final Lock lock = new ReentrantLock();
  15. private final Condition notFull = lock.newCondition();
  16. private final Condition notEmpty = lock.newCondition();
  17. public MyBlocingQueue2 ( int limit) {
  18. this.limit = limit;
  19. this.list = new LinkedList<E>();
  20. }
  21. public void put (E e) throws InterruptedException {
  22. lock. lock();
  23. try {
  24. while (list.size() == limit){
  25. notFull. await();
  26. }
  27. list. add(e);
  28. notEmpty.signalAll();
  29. } finally {
  30. lock.unlock();
  31. }
  32. }
  33. public E take () throws InterruptedException {
  34. lock. lock();
  35. try {
  36. while (list.size() == 0){
  37. notEmpty. await();
  38. }
  39. E remove = (E) list. remove( 0);
  40. notFull.signalAll();
  41. return remove;
  42. } finally {
  43. lock.unlock();
  44. }
  45. }
  46. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

用Java写代码来解决生产者——消费者问题。

与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。在Java中怎么解决生产者——消费者问题,当然有很多解决方法,我已经分享了一种用阻塞队列实现的方法。有些时候他们甚至会问怎么实现哲学家进餐问题。

生产者、消费者有很多的实现方法: 
- 用wait() / notify()方法 
- 用Lock的多Condition方法 
- BlockingQueue阻塞队列方法

可以发现在上面实现阻塞队列题中,BlockingQueue的实现基本都用到了类似的实现,将BlockingQueue的实现方式稍微包装一下就成了一个生产者-消费者模式了。


    
    
  1. import java.util.Random;
  2. import java.util.concurrent.ArrayBlockingQueue;
  3. import java.util.concurrent.BlockingQueue;
  4. /**
  5. * 用阻塞队列快速实现生产者-消费者
  6. * @author xuexiaolei
  7. * @version 2017年11月01日
  8. */
  9. public class ProduceAndConsumer {
  10. public static void main(String[] args) {
  11. final BlockingQueue<Integer> list = new ArrayBlockingQueue<Integer>( 10);
  12. Procude procude = new Procude( list);
  13. Consumer consumer = new Consumer( list);
  14. procude.start();
  15. consumer.start();
  16. }
  17. static class Procude extends Thread{
  18. private final BlockingQueue<Integer> list;
  19. Procude(BlockingQueue<Integer> list) {
  20. this. list = list;
  21. }
  22. @Override public void run() {
  23. while( true){
  24. try {
  25. Integer take = list.take();
  26. System.out.println( "消费数据:" + take);
  27. // Thread.sleep(1000);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }
  34. static class Consumer extends Thread{
  35. private final BlockingQueue<Integer> list;
  36. Consumer(BlockingQueue<Integer> list) {
  37. this. list = list;
  38. }
  39. @Override public void run() {
  40. while ( true){
  41. try {
  42. int i = new Random().nextInt( 100);
  43. list.put(i);
  44. System.out.println( "生产数据:" + i);
  45. Thread.sleep( 1000);
  46. } catch (InterruptedException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }
  51. }
  52. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

此处不再详细地写另外几种实现方式了:wait() / notify()方法、Lock的多Condition方法、信号量等,甚至可以考虑用CyclicBarrier、CountDownLatch也可以实现生产者-消费者的,难易程度、效率不一样罢了。

用Java写一个会导致死锁的程序,你将怎么解决?

这是我最喜欢的Java线程面试问题,因为即使死锁问题在写多线程并发程序时非常普遍,但是很多侯选者并不能写deadlock free code(无死锁代码?),他们很挣扎。只要告诉他们,你有N个资源和N个线程,并且你需要所有的资源来完成一个操作。为了简单这里的n可以替换为2,越大的数据会使问题看起来更复杂。通过避免Java中的死锁来得到关于死锁的更多信息。


    
    
  1. /**
  2. * 简单死锁程序
  3. * lockA、lockB分别是两个资源,线程A、B必须同是拿到才能工作
  4. * 但A线程先拿lockA、再拿lockB
  5. * 线程先拿lockB、再拿lockA
  6. * @author xuexiaolei
  7. * @version 2017年11月01日
  8. */
  9. public class SimpleDeadLock {
  10. public static void main(String[] args) {
  11. Object lockA = new Object();
  12. Object lockB = new Object();
  13. A a = new A(lockA, lockB);
  14. B b = new B(lockA, lockB);
  15. a.start();
  16. b.start();
  17. }
  18. static class A extends Thread{
  19. private final Object lockA;
  20. private final Object lockB;
  21. A(Object lockA, Object lockB) {
  22. this.lockA = lockA;
  23. this.lockB = lockB;
  24. }
  25. @Override public void run() {
  26. synchronized (lockA){
  27. try {
  28. Thread.sleep( 1000);
  29. synchronized (lockB){
  30. System.out.println( "Hello A");
  31. }
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }
  37. }
  38. static class B extends Thread{
  39. private final Object lockA;
  40. private final Object lockB;
  41. B(Object lockA, Object lockB) {
  42. this.lockA = lockA;
  43. this.lockB = lockB;
  44. }
  45. @Override public void run() {
  46. synchronized (lockB){
  47. try {
  48. Thread.sleep( 1000);
  49. synchronized (lockA){
  50. System.out.println( "Hello B");
  51. }
  52. } catch (InterruptedException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56. }
  57. }
  58. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

产生死锁的四个必要条件: 
- 互斥条件:一个资源每次只能被一个进程使用。 
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免死锁? 
- 从死锁的四个必要条件来看,破坏其中的任意一个条件就可以避免死锁。但互斥条件是由资源本身决定的,不剥夺条件一般无法破坏,要实现的话得自己写更多的逻辑。 
- 避免无限期的等待:用Lock.tryLock(),wait/notify等方法写出请求一定时间后,放弃已经拥有的锁的程序。 
- 注意锁的顺序:以固定的顺序获取锁,可以避免死锁。 
- 开放调用:即只对有请求的进行封锁。你应当只想你要运行的资源获取封锁,比如在上述程序中我在封锁的完全的对象资源。但是如果我们只对它所属领域中的一个感兴趣,那我们应当封锁住那个特殊的领域而并非完全的对象。 
- 最后,如果能避免使用多个锁,甚至写出无锁的线程安全程序是再好不过了。

什么是原子操作,Java中的原子操作是什么?

非常简单的java线程面试问题,接下来的问题是你是否需要同步一个原子操作。

原子操作是不可分割的操作,一个原子操作中间是不会被其他线程打断的,所以不需要同步一个原子操作。 
多个原子操作合并起来后就不是一个原子操作了,就需要同步了。 
i++不是一个原子操作,它包含 读取-修改-写入 操作,在多线程状态下是不安全的。 
另外,java内存模型允许将64位的读操作或写操作分解为2个32位的操作,所以对long和double类型的单次读写操作并不是原子的,注意使用volitile使他们成为原子操作。

Java中的volatile关键是什么作用?怎样使用它?在Java中它跟synchronized方法有什么不同?

自从Java 5和Java内存模型改变以后,基于volatile关键字的线程问题越来越流行。应该准备好回答关于volatile变量怎样在并发环境中确保可见性。

volatile关键字的作用是:保证变量的可见性。 
在java内存结构中,每个线程都是有自己独立的内存空间(此处指的线程栈)。当需要对一个共享变量操作时,线程会将这个数据从主存空间复制到自己的独立空间内进行操作,然后在某个时刻将修改后的值刷新到主存空间。这个中间时间就会发生许多奇奇怪怪的线程安全问题了,volatile就出来了,它保证读取数据时只从主存空间读取,修改数据直接修改到主存空间中去,这样就保证了这个变量对多个操作线程的可见性了。换句话说,被volatile修饰的变量,能保证该变量的 单次读或者单次写 操作是原子的。

但是线程安全是两方面需要的 原子性(指的是多条操作)和可见性。volatile只能保证可见性,synchronized是两个均保证的。 
volatile轻量级,只能修饰变量;synchronized重量级,还可修饰方法。 
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。

什么是竞争条件(race condition)?你怎样发现和解决的?

这是一道出现在多线程面试的高级阶段的问题。大多数的面试官会问最近你遇到的竞争条件,以及你是怎么解决的。有些时间他们会写简单的代码,然后让你检测出代码的竞争条件。可以参考我之前发布的关于Java竞争条件的文章。在我看来这是最好的java线程面试问题之一,它可以确切的检测候选者解决竞争条件的经验。关于这方面最好的书是《java并发编程实战》。

竞争条件,在《java并发编程实战》叫做竞态条件:指设备或系统出现不恰当的执行时序,而得到不正确的结果。

下面是个最简单的例子,是一个单例模式实现的错误示范:


    
    
  1. @NotThreadSafe
  2. public class LazyInitRace {
  3. private ExpensiveObject instance = null;
  4. public ExpensiveObject getInstance () {
  5. if (instance == null)
  6. instance = new ExpensiveObject();
  7. return instance;
  8. }
  9. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在上述例子中,表现一种很常见的竞态条件类型:“先检查后执行”。根据某个检查结果来执行进一步的操作,但很有可能这个检查结果是失效的!还有很常见的竞态条件“读取-修改-写入”三连,在多线程条件下,三个小操作并不一定会放在一起执行的。

如何对待竞态条件? 
首先,警惕复合操作,当多个原子操作合在一起的时候,并不一定仍然是一个原子操作,此时需要用同步的手段来保证原子性。 
另外,使用本身是线程安全的类,这样在很大程度上避免了未知的风险。

你将如何使用thread dump?你将如何分析Thread dump?

在UNIX中你可以使用kill -3,然后thread dump将会打印日志,在windows中你可以使用”CTRL+Break”。非常简单和专业的线程面试问题,但是如果他问你怎样分析它,就会很棘手。

SIGQUIT(kill -3 pid)用来打印Java进程trace,并不会影响程序运行,不用担心他把程序杀死了;SIGUSR1(kill -10 pid)可触发进程进行一次强制GC。

java线程的状态转换介绍

后续分析要用到,所以此处穿插一下这个点: 
java线程的状态转换

  • 新建状态(New) 
    用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。
  • 就绪状态(Runnable) 
    当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。
  • 运行状态(Running) 
    处于这个状态的线程占用CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。
  • 阻塞状态(Blocked) 
    阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。 
    阻塞状态可分为以下3种: 
    1. 位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
    2. 位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
    3. 其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。
  • 死亡状态(Dead) 
    当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。

我们运行之前的那个死锁代码SimpleDeadLock.java,然后尝试输出信息(/*这是注释,作者自己加的*/):


    
    
  1. /* 时间,jvm信息 */
  2. 2017 - 11 - 01 17: 36: 28
  3. Full thread dump Java HotSpot(TM) 64-Bit Server VM ( 25.144-b01 mixed mode):
  4. /* 线程名称:DestroyJavaVM
  5. 编号:#13
  6. 优先级:5
  7. 系统优先级:0
  8. jvm内部线程id:0x0000000001c88800
  9. 对应系统线程id(NativeThread ID):0x1c18
  10. 线程状态: waiting on condition [0x0000000000000000] (等待某个条件)
  11. 线程详细状态:java.lang.Thread.State: RUNNABLE 及之后所有*/
  12. "DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000001c88800 nid=0x1c18 waiting on condition [0x0000000000000000]
  13. java .lang .Thread .State: RUNNABLE
  14. "Thread-1" #12 prio=5 os_prio=0 tid=0x0000000018d49000 nid=0x17b8 waiting for monitor entry [0x0000000019d7f000]
  15. /* 线程状态:阻塞(在对象同步上)
  16. 代码位置:at com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:<span class="hljs-number">56</span>)</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"> 等待锁:<span class="hljs-number">0x00000000d629b4d8</span> </span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"> 已经获得锁:<span class="hljs-number">0x00000000d629b4e8</span>*/</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: BLOCKED (<span class="hljs-keyword">on</span> <span class="hljs-built_in">object</span> monitor)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.leo</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.interview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SimpleDeadLock</span>$B.run(SimpleDeadLock.java:56)
  17. - waiting to lock < 0x00000000d629b4d8> (a java .lang .Object)
  18. - locked < 0x00000000d629b4e8> (a java .lang .Object)
  19. "Thread-0" #11 prio=5 os_prio=0 tid=0x0000000018d44000 nid=0x1ebc waiting for monitor entry [0x000000001907f000]
  20. java .lang .Thread .State: BLOCKED ( on object monitor)
  21. at com .leo .interview .SimpleDeadLock$A<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(SimpleDeadLock<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">34</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="29"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">to</span> lock &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4e8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="30"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4d8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="31"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="32"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Service Thread"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#10 daemon prio=9 os_prio=0 tid=0x0000000018ca5000 nid=0x1264 runnable [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="33"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="34"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="35"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C1 CompilerThread2"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#9 daemon prio=9 os_prio=2 tid=0x0000000018c46000 nid=0xb8c waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="36"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="37"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="38"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C2 CompilerThread1"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#8 daemon prio=9 os_prio=2 tid=0x0000000018be4800 nid=0x1db4 waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="39"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="40"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="41"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C2 CompilerThread0"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#7 daemon prio=9 os_prio=2 tid=0x0000000018be3800 nid=0x810 waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="42"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="43"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="44"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Monitor Ctrl-Break"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#6 daemon prio=5 os_prio=0 tid=0x0000000018bcc800 nid=0x1c24 runnable [0x00000000193ce000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="45"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="46"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.socketRead</span>0(Native Method)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="47"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.socketRead</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">116</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="48"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">171</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="49"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">141</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="50"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readBytes</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">284</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="51"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.implRead</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">326</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="52"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">178</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="53"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d632b928</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="54"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(InputStreamReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">184</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="55"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.fill</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">161</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="56"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readLine</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">324</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="57"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d632b928</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="58"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readLine</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">389</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="59"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.intellij</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.rt</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.execution</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.application</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.AppMainV</span>2$ 1 .run(AppMainV2 .java: 64)
  22. "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000017781800 nid=0x524 runnable [0x0000000000000000]
  23. java .lang .Thread .State: RUNNABLE
  24. "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001778f800 nid=0x1b08 waiting on condition [0x0000000000000000]
  25. java .lang .Thread .State: RUNNABLE
  26. "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001776a800 nid=0xdac in Object.wait() [0x0000000018b6f000]
  27. java .lang .Thread .State: WAITING ( on object monitor)
  28. at java .lang .Object .wait(Native Method)
  29. - waiting on < 0x00000000d6108ec8> (a java .lang .ref .ReferenceQueue$Lock)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="71"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ReferenceQueue</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.remove</span>(ReferenceQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">143</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="72"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d6108ec8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ReferenceQueue</span>$Lock)
  30. at java .lang .ref .ReferenceQueue .remove(ReferenceQueue .java: 164)
  31. at java .lang .ref .Finalizer$FinalizerThread<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(Finalizer<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">209</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="75"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="76"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Reference Handler"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#2 daemon prio=10 os_prio=2 tid=0x0000000017723800 nid=0x1670 in Object.wait() [0x00000000189ef000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="77"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: WAITING (<span class="hljs-keyword">on</span> <span class="hljs-built_in">object</span> monitor)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="78"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.wait</span>(Native Method)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="79"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">on</span> &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d6106b68</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Reference</span>$Lock)
  32. at java .lang .Object .wait( Object .java: 502)
  33. at java .lang .ref .Reference .tryHandlePending(Reference .java: 191)
  34. - locked < 0x00000000d6106b68> (a java .lang .ref .Reference$Lock)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="83"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Reference</span>$ReferenceHandler .run(Reference .java: 153)
  35. "VM Thread" os_prio= 2 tid= 0x000000001771b800 nid= 0x604 runnable
  36. "GC task thread#0 (ParallelGC)" os_prio= 0 tid= 0x0000000001c9d800 nid= 0x9f0 runnable
  37. "GC task thread#1 (ParallelGC)" os_prio= 0 tid= 0x0000000001c9f000 nid= 0x154c runnable
  38. "GC task thread#2 (ParallelGC)" os_prio= 0 tid= 0x0000000001ca0800 nid= 0xcd0 runnable
  39. "GC task thread#3 (ParallelGC)" os_prio= 0 tid= 0x0000000001ca2000 nid= 0x1e58 runnable
  40. "VM Periodic Task Thread" os_prio= 2 tid= 0x0000000018c5a000 nid= 0x1b58 waiting on condition
  41. JNI global references: 33
  42. /* 此处可以看待死锁的相关信息! */
  43. Found one Java-level deadlock:
  44. =============================
  45. "Thread-1":
  46. waiting to lock monitor 0x0000000017729fc8 ( object 0x00000000d629b4d8, a java .lang .Object),
  47. which is held by "Thread-0"
  48. "Thread-0":
  49. waiting to lock monitor 0x0000000017727738 ( object 0x00000000d629b4e8, a java .lang .Object),
  50. which is held by "Thread-1"
  51. Java stack information for the threads listed above:
  52. ===================================================
  53. "Thread-1":
  54. at com .leo .interview .SimpleDeadLock$B<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(SimpleDeadLock<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">56</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="114"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">to</span> lock &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4d8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="115"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4e8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="116"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Thread-0"</span></span>:</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="117"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.leo</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.interview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SimpleDeadLock</span>$A .run(SimpleDeadLock .java: 34)
  55. - waiting to lock < 0x00000000d629b4e8> (a java .lang .Object)
  56. - locked < 0x00000000d629b4d8> (a java .lang .Object)
  57. Found 1 deadlock.
  58. /* 内存使用状况,详情得看JVM方面的书 */
  59. Heap
  60. PSYoungGen total 37888K, used 4590K [ 0x00000000d6100000, 0x00000000d8b00000, 0x0000000100000000)
  61. eden space 32768K, 14% used [ 0x00000000d6100000, 0x00000000d657b968, 0x00000000d8100000)
  62. from space 5120K, 0% used [ 0x00000000d8600000, 0x00000000d8600000, 0x00000000d8b00000)
  63. to space 5120K, 0% used [ 0x00000000d8100000, 0x00000000d8100000, 0x00000000d8600000)
  64. ParOldGen total 86016K, used 0K [ 0x0000000082200000, 0x0000000087600000, 0x00000000d6100000)
  65. object space 86016K, 0% used [ 0x0000000082200000, 0x0000000082200000, 0x0000000087600000)
  66. Metaspace used 3474K, capacity 4500K, committed 4864K, reserved 1056768K
  67. class space used 382K, capacity 388K, committed 512K, reserved 1048576K
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132

为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

这是另一个非常经典的java多线程面试问题。这也是我刚开始写线程程序时候的困惑。现在这个问题通常在电话面试或者是在初中级Java面试的第一轮被问到。这个问题的回答应该是这样的,当你调用start()方法时你将创建新的线程,并且执行在run()方法里的代码。但是如果你直接调用run()方法,它不会创建新的线程也不会执行调用线程的代码。

简单点来说: 
new一个Thread,线程进入了新建状态;调用start()方法,线程进入了就绪状态,当分配到时间片后就可以开始运行了。 
start()会执行线程的相应准备工作,然后自动执行run()方法的内容。是真正的多线程工作。 
而直接执行run()方法,会把run方法当成一个mian线程下的普通方法去执行,并不会在某个线程中执行它,这并不是多线程工作。

Java中你怎样唤醒一个阻塞的线程?

这是个关于线程和阻塞的棘手的问题,它有很多解决方法。如果线程遇到了IO阻塞,我并且不认为有一种方法可以中止线程。如果线程因为调用wait()、sleep()、或者join()方法而导致的阻塞,你可以中断线程,并且通过抛出InterruptedException来唤醒它。我之前写的《How to deal with blocking methods in java》有很多关于处理线程阻塞的信息。

这个我们先简单粗暴地对某些阻塞方法进行分类: 
- 会抛出InterruptedException的方法:wait、sleep、join、Lock.lockInterruptibly等,针对这类方法,我们在线程内部处理好异常(要不完全内部处理,要不把这个异常抛出去),然后就可以实现唤醒。 
- 不会抛InterruptedException的方法:Socket的I/O,同步I/O,Lock.lock等。对于I/O类型,我们可以关闭他们底层的通道,比如Socket的I/O,关闭底层套接字,然后抛出异常处理就好了;比如同步I/O,关闭底层Channel然后处理异常。对于Lock.lock方法,我们可以改造成Lock.lockInterruptibly方法去实现。

在Java中CycliBarriar和CountdownLatch有什么区别?

这个线程问题主要用来检测你是否熟悉JDK5中的并发包。这两个的区别是CyclicBarrier可以重复使用已经通过的障碍,而CountdownLatch不能重复使用。

还要注意一点的区别: 
CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 
CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。 
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待,而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。 
从api上理解就是CountdownLatch有主要配合使用两个方法countDown()和await(),countDown()是做事的线程用的方法,await()是等待事情完成的线程用个方法,这两种线程是可以分开的(下面例子:CountdownLatchTest2),当然也可以是同一组线程(下面例子:CountdownLatchTest);CyclicBarrier只有一个方法await(),指的是做事线程必须大家同时等待,必须是同一组线程的工作。

CountdownLatch例子:


    
    
  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. /**
  5. * 线程都准备完成后一起执行的例子
  6. * @author xuexiaolei
  7. * @version 2017年11月02日
  8. */
  9. public class CountdownLatchTest {
  10. private final static int THREAD_NUM = 10;
  11. public static void main (String[] args) {
  12. CountDownLatch lock = new CountDownLatch(THREAD_NUM);
  13. ExecutorService exec = Executors.newCachedThreadPool();
  14. for ( int i = 0; i < THREAD_NUM; i++) {
  15. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  16. }
  17. exec.shutdown();
  18. }
  19. static class CountdownLatchTask implements Runnable{
  20. private final CountDownLatch lock;
  21. private final String threadName;
  22. CountdownLatchTask(CountDownLatch lock, String threadName) {
  23. this.lock = lock;
  24. this.threadName = threadName;
  25. }
  26. @Override public void run () {
  27. //循环多次是为了证明,CountdownLatch只会阻挡一次
  28. for ( int i = 0; i < 3; i++) {
  29. System.out.println(threadName + " 准备完成");
  30. lock.countDown();
  31. try {
  32. lock.await();
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. System.out.println(threadName + " 执行完成");
  37. }
  38. }
  39. }
  40. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

    
    
  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. /**
  5. * 各个线程执行完成后,主线程做总结性工作的例子
  6. * @author xuexiaolei
  7. * @version 2017年11月02日
  8. */
  9. public class CountdownLatchTest2 {
  10. private final static int THREAD_NUM = 10;
  11. public static void main (String[] args) {
  12. CountDownLatch lock = new CountDownLatch(THREAD_NUM);
  13. ExecutorService exec = Executors.newCachedThreadPool();
  14. for ( int i = 0; i < THREAD_NUM; i++) {
  15. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  16. }
  17. try {
  18. lock.await();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. System.out.println( "大家都执行完成了,做总结性工作");
  23. exec.shutdown();
  24. }
  25. static class CountdownLatchTask implements Runnable{
  26. private final CountDownLatch lock;
  27. private final String threadName;
  28. CountdownLatchTask(CountDownLatch lock, String threadName) {
  29. this.lock = lock;
  30. this.threadName = threadName;
  31. }
  32. @Override public void run () {
  33. System.out.println(threadName + " 执行完成");
  34. lock.countDown();
  35. }
  36. }
  37. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

CyclicBarrier例子:


    
    
  1. import java.util.concurrent.*;
  2. /**
  3. *
  4. * @author xuexiaolei
  5. * @version 2017年11月02日
  6. */
  7. public class CyclicBarrierTest {
  8. private final static int THREAD_NUM = 10;
  9. public static void main (String[] args) {
  10. CyclicBarrier lock = new CyclicBarrier(THREAD_NUM, new Runnable() {
  11. @Override public void run () {
  12. System.out.println( "大家都准备完成了");
  13. }
  14. });
  15. ExecutorService exec = Executors.newCachedThreadPool();
  16. for ( int i = 0; i < THREAD_NUM; i++) {
  17. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  18. }
  19. exec.shutdown();
  20. }
  21. static class CountdownLatchTask implements Runnable{
  22. private final CyclicBarrier lock;
  23. private final String threadName;
  24. CountdownLatchTask(CyclicBarrier lock, String threadName) {
  25. this.lock = lock;
  26. this.threadName = threadName;
  27. }
  28. @Override public void run () {
  29. for ( int i = 0; i < 3; i++) {
  30. System.out.println(threadName + " 准备完成");
  31. try {
  32. lock.await();
  33. } catch (BrokenBarrierException e) {
  34. e.printStackTrace();
  35. } catch (InterruptedException e) {
  36. e.printStackTrace();
  37. }
  38. System.out.println(threadName + " 执行完成");
  39. }
  40. }
  41. }
  42. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

什么是不可变对象,它对写并发应用有什么帮助?

另一个多线程经典面试问题,并不直接跟线程有关,但间接帮助很多。这个java面试问题可以变的非常棘手,如果他要求你写一个不可变对象,或者问你为什么String是不可变的。

immutable Objects(不可变对象)就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对他们的改变都是产生了新的immutable的对象,而mutable Objects(可变对象)就是那些创建后,状态可以被改变的Objects.

如何在Java中写出Immutable的类? 
1. immutable对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象。 
2. immutable类的所有的属性都应该是final的。 
3. 对象必须被正确的创建,比如:对象引用在对象创建过程中不能泄露(leak)。 
4. 对象应该是final的,以此来限制子类继承父类,以避免子类改变了父类的immutable特性。 
5. 如果类中包含mutable类对象,那么返回给客户端的时候,返回该对象的一个拷贝,而不是该对象本身(该条可以归为第一条中的一个特例)

使用Immutable类的好处: 
1. Immutable对象是线程安全的,可以不用被synchronize就在并发环境中共享 
2.Immutable对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程间共享 
3. Immutable对象提高了程序的性能,因为它减少了synchroinzed的使用 
4. Immutable对象是可以被重复使用的,你可以将它们缓存起来重复使用,就像字符串字面量和整型数字一样。你可以使用静态工厂方法来提供类似于valueOf()这样的方法,它可以从缓存中返回一个已经存在的Immutable对象,而不是重新创建一个。


    
    
  1. /**
  2. * 不可变对象
  3. * @author xuexiaolei
  4. * @version 2017年11月03日
  5. */
  6. public class ImmutableObjectPerson {
  7. private final String name;
  8. private final String sex;
  9. public ImmutableObjectPerson (String name, String sex) {
  10. this.name = name;
  11. this.sex = sex;
  12. }
  13. public String getName () {
  14. return name;
  15. }
  16. public String getSex () {
  17. return sex;
  18. }
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

你在多线程环境中遇到的常见的问题是什么?你是怎么解决它的?

多线程和并发程序中常遇到的有Memory-interface、竞争条件、死锁、活锁和饥饿。问题是没有止境的,如果你弄错了,将很难发现和调试。这是大多数基于面试的,而不是基于实际应用的Java线程问题。

此类问题请大家面试的时候提前准备,方便交流,如果实在找不出来,可以想想自己平时解决问题的思路,总结下来告诉考官。

Java并发编程问题是面试过程中很容易遇到的问题,提前准备是解决问题的最好办法,将试题总结起来,时常查看会有奇效。

现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。

核心:

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。 
比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。 
想要更深入了解,建议看一下join的源码,也很简单的,使用wait方法实现的。

t.join(); //调用join方法,等待线程t执行完毕 
t.join(1000); //等待 t 线程,等待时间是1000毫秒。

代码实现:


  
  
  1. public static void main (String[] args) {
  2. method01();
  3. method02();
  4. }
  5. /**
  6. * 第一种实现方式,顺序写死在线程代码的内部了,有时候不方便
  7. */
  8. private static void method01 () {
  9. Thread t1 = new Thread( new Runnable() {
  10. @Override public void run () {
  11. System.out.println( ”t1 is finished”);
  12. }
  13. });
  14. Thread t2 = new Thread( new Runnable() {
  15. @Override public void run () {
  16. try {
  17. t1.join();
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. System.out.println( ”t2 is finished”);
  22. }
  23. });
  24. Thread t3 = new Thread( new Runnable() {
  25. @Override public void run () {
  26. try {
  27. t2.join();
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. System.out.println( ”t3 is finished”);
  32. }
  33. });
  34. t3.start();
  35. t2.start();
  36. t1.start();
  37. }
  38. /**
  39. * 第二种实现方式,线程执行顺序可以在方法中调换
  40. */
  41. private static void method02 (){
  42. Runnable runnable = new Runnable() {
  43. @Override public void run () {
  44. System.out.println(Thread.currentThread().getName() + ”执行完成”);
  45. }
  46. };
  47. Thread t1 = new Thread(runnable, ”t1”);
  48. Thread t2 = new Thread(runnable, ”t2”);
  49. Thread t3 = new Thread(runnable, ”t3”);
  50. try {
  51. t1.start();
  52. t1.join();
  53. t2.start();
  54. t2.join();
  55. t3.start();
  56. t3.join();
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?

这个题的原答案我认为不是很全面。 
Lock接口 和 ReadWriteLock接口 如下:


  
  
  1. public interface Lock {
  2. void lock();
  3. void lockInterruptibly() throws InterruptedException;
  4. boolean tryLock();
  5. boolean tryLock( long time, TimeUnit unit) throws InterruptedException;
  6. void unlock();
  7. Condition newCondition();
  8. }
  9. public interface ReadWriteLock {
  10. Lock readLock();
  11. Lock writeLock();
  12. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

整体上来说Lock是synchronized的扩展版,Lock提供了无条件的、可轮询的(tryLock方法)、定时的(tryLock带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition方法)锁操作。另外Lock的实现类基本都支持非公平锁(默认)和公平锁,synchronized只支持非公平锁,当然,在大部分情况下,非公平锁是高效的选择。

ReadWriteLock是对Lock的运用,具体的实现类是 ReentrantReadWriteLock ,下面用这个类来实现读写类型的高效缓存:


  
  
  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import java.util.Random;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.locks.Lock;
  7. import java.util.concurrent.locks.ReadWriteLock;
  8. import java.util.concurrent.locks.ReentrantReadWriteLock;
  9. /**
  10. * 用ReadWriteLock读写锁来实现一个高效的Map缓存
  11. * Created by LEO on 2017/10/30.
  12. */
  13. public class ReaderAndWriter<K, V> {
  14. private final ReadWriteLock lock = new ReentrantReadWriteLock();
  15. private final Lock readLock = lock.readLock();
  16. private final Lock writeLock = lock.writeLock();
  17. private final Map< K, V> map;
  18. public ReaderAndWriter( Map< K, V> map) {
  19. this. map = map;
  20. }
  21. /************* 这是用lock()方法写的 ********************/
  22. // public V put(K key, V value){
  23. // writeLock.lock();
  24. // try {
  25. // return map.put(key, value);
  26. // }finally {
  27. // writeLock.unlock();
  28. // }
  29. // }
  30. // public V get(K key){
  31. // readLock.lock();
  32. // try {
  33. // return map.get(key);
  34. // }finally {
  35. // readLock.unlock();
  36. // }
  37. // }
  38. /************* 这是用tryLock()方法写的 ********************/
  39. public V put( K key, V value){
  40. while ( true){
  41. if(writeLock.tryLock()){
  42. try {
  43. System.out. println( "put "+ key + " = " + value);
  44. return map.put(key, value);
  45. } finally {
  46. writeLock.unlock();
  47. }
  48. }
  49. }
  50. }
  51. public V get( K key){
  52. while ( true){
  53. if (readLock.tryLock()) {
  54. try {
  55. V v = map. get(key);
  56. System.out. println( "get "+ key + " = " + v);
  57. return v;
  58. } finally {
  59. readLock.unlock();
  60. }
  61. }
  62. }
  63. }
  64. /******************** 下面是测试区 *********************************/
  65. public static void main( String[] args) {
  66. final ReaderAndWriter< String, Integer> rw = new ReaderAndWriter<>( new HashMap<>());
  67. ExecutorService exec = Executors.newCachedThreadPool();
  68. for (int i = 0; i < 100; i++) {
  69. exec.execute( new TestRunnable(rw));
  70. }
  71. exec.shutdown();
  72. }
  73. static class TestRunnable implements Runnable{
  74. private final ReaderAndWriter< String, Integer> rw;
  75. private final String KEY = "x";
  76. TestRunnable( ReaderAndWriter< String, Integer> rw) {
  77. this.rw = rw;
  78. }
  79. @Override
  80. public void run() {
  81. Random random = new Random();
  82. int r = random.nextInt( 100);
  83. //生成随机数,小于30的写入缓存,大于等于30则读取数字
  84. if (r < 30){
  85. rw.put( KEY, r);
  86. } else {
  87. rw. get( KEY);
  88. }
  89. }
  90. }
  91. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

在java中wait和sleep方法的不同?

通常会在电话面试中经常被问到的Java线程面试问题。 
最大的不同是在等待时wait会释放锁,而sleep一直持有锁。Wait通常被用于线程间交互,sleep通常被用于暂停执行。

此处我想理一下Java多线程的基础知识: 
- Java的多线程锁是挂在对象上的,并不是在方法上的。即每个对象都有一个锁,当遇到类似synchronized的同步需要时,就会监视(monitor)每个想使用本对象的线程按照一定的规则来访问,规则也就是在同一时间内只能有一个线程能访问此对象。 
- Java中获取锁的单位是线程。当线程A获取了对象B的锁,也就是对象B的持有标记上写的是线程A的唯一标识,在需要同步的情况下的话,只有线程A能访问对象B。 
- Thread常用方法有:start/stop/yield/sleep/interrupt/join等,他们是线程级别的方法,所以并不会太关心锁的具体逻辑。 
- Object的线程有关方法是:wait/wait(事件参数)/notify/notifyAll,他们是对象的方法,所以使用的时候就有点憋屈了,必须当前线程获取了本对象的锁才能使用,否则会报异常。但他们能更细粒度的控制锁,可以释放锁。

用Java实现阻塞队列。

这是一个相对艰难的多线程面试问题,它能达到很多的目的。第一,它可以检测侯选者是否能实际的用Java线程写程序;第二,可以检测侯选者对并发场景的理解,并且你可以根据这个问很多问题。如果他用wait()和notify()方法来实现阻塞队列,你可以要求他用最新的Java 5中的并发类来再写一次。

下面是实现了阻塞的take和put方法的阻塞队列(分别用synchronized 和 wait/notify 实现):


  
  
  1. import java.util.LinkedList;
  2. import java.util.List;
  3. import java.util.Random;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. /**
  7. * 实现了阻塞的take和put方法的阻塞队列
  8. * 分别用synchronized 和 wait/notify 实现
  9. * @author xuexiaolei
  10. * @version 2017年11月01日
  11. */
  12. public class MyBlocingQueue< E> {
  13. private final List list;
  14. private final int limit; //有大小限制的
  15. public MyBlocingQueue ( int limit) {
  16. this.limit = limit;
  17. this.list = new LinkedList<E>();
  18. }
  19. //这是用synchronized写的,在list空或者满的时候效率会低,因为会一直轮询
  20. // public void put(E e){
  21. // while(true){
  22. // synchronized (list){
  23. // if (list.size() < limit) {
  24. // System.out.println("list : " + list.toString());
  25. // System.out.println("put : " + e);
  26. // list.add(e);
  27. // return;
  28. // }
  29. // }
  30. // }
  31. // }
  32. // public E take(){
  33. // while (true) {
  34. // synchronized (list) {
  35. // if (list.size() > 0){
  36. // System.out.println("list : " + list.toString());
  37. // E remove = (E) list.remove(0);
  38. // System.out.println("take : " + remove);
  39. // return remove;
  40. // }
  41. // }
  42. // }
  43. // }
  44. //用wait,notify写的,在list空或者满的时候效率会高一点,因为wait释放锁,然后等待唤醒
  45. public synchronized void put (E e){
  46. while (list.size() == limit){
  47. try {
  48. wait();
  49. } catch (InterruptedException e1) {
  50. e1.printStackTrace();
  51. }
  52. }
  53. System. out.println( "list : " + list.toString());
  54. System. out.println( "put : " + e);
  55. list. add(e);
  56. notifyAll();
  57. }
  58. public synchronized E take () {
  59. while (list.size() == 0){
  60. try {
  61. wait();
  62. } catch (InterruptedException e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. System. out.println( "list : " + list.toString());
  67. E remove = (E) list. remove( 0);
  68. System. out.println( "take : " + remove);
  69. notifyAll();
  70. return remove;
  71. }
  72. /******************** 下面是测试区 *********************************/
  73. public static void main (String[] args) {
  74. final MyBlocingQueue<Integer> myBlocingQueue = new MyBlocingQueue( 10);
  75. ExecutorService exec = Executors.newCachedThreadPool();
  76. for ( int i = 0; i < 100; i++) {
  77. exec.execute( new TestRunnable(myBlocingQueue));
  78. }
  79. exec.shutdown();
  80. }
  81. static class TestRunnable implements Runnable{
  82. private final MyBlocingQueue<Integer> myBlocingQueue;
  83. TestRunnable(MyBlocingQueue<Integer> myBlocingQueue) {
  84. this.myBlocingQueue = myBlocingQueue;
  85. }
  86. @ Override
  87. public void run () {
  88. Random random = new Random();
  89. int r = random.nextInt( 100);
  90. //生成随机数,按照一定比率读取或者放入,可以更改!!!
  91. if (r < 30){
  92. myBlocingQueue.put(r);
  93. } else {
  94. myBlocingQueue.take();
  95. }
  96. }
  97. }
  98. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

BlockingQueue介绍:

Java5中提供了BlockingQueue的方法,并且有几个实现,在此介绍一下。

BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

Throws exception Special value Blocks Times out
add(e) offer(e) put(e) offer(Object, long, TimeUnit)
remove() poll() take() poll(long, TimeUnit)
element() peek()    

- Throws exception 抛异常:如果试图的操作无法立即执行,抛一个异常。 
- Special value 特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false) 
- Blocks 阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。 
- Times out 超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是true / false)。

BlockingQueue 的实现类 
ArrayBlockingQueue:ArrayBlockingQueue 是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注:因为它是基于数组实现的,也就具有数组的特性:一旦初始化,大小就无法修改)。 
DelayQueue:DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现 java.util.concurrent.Delayed 接口。 
LinkedBlockingQueue:LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。 
PriorityBlockingQueue:PriorityBlockingQueue 是一个无界的并发队列。它使用了和类 java.util.PriorityQueue 一样的排序规则。你无法向这个队列中插入 null 值。所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。 
SynchronousQueue:SynchronousQueue 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点。

BlocingQueue的实现大多是通过 lock锁的多条件(condition)阻塞控制,下面我们自己写一个简单版:


  
  
  1. import java.util.LinkedList;
  2. import java.util.List;
  3. import java.util.concurrent.locks.Condition;
  4. import java.util.concurrent.locks.Lock;
  5. import java.util.concurrent.locks.ReentrantLock;
  6. /**
  7. * 模仿ArrayBlockingQueue实现阻塞队列
  8. * @author xuexiaolei
  9. * @version 2017年11月01日
  10. */
  11. public class MyBlocingQueue2< E> {
  12. private final List list;
  13. private final int limit; //有大小限制的
  14. private final Lock lock = new ReentrantLock();
  15. private final Condition notFull = lock.newCondition();
  16. private final Condition notEmpty = lock.newCondition();
  17. public MyBlocingQueue2 ( int limit) {
  18. this.limit = limit;
  19. this.list = new LinkedList<E>();
  20. }
  21. public void put (E e) throws InterruptedException {
  22. lock. lock();
  23. try {
  24. while (list.size() == limit){
  25. notFull. await();
  26. }
  27. list. add(e);
  28. notEmpty.signalAll();
  29. } finally {
  30. lock.unlock();
  31. }
  32. }
  33. public E take () throws InterruptedException {
  34. lock. lock();
  35. try {
  36. while (list.size() == 0){
  37. notEmpty. await();
  38. }
  39. E remove = (E) list. remove( 0);
  40. notFull.signalAll();
  41. return remove;
  42. } finally {
  43. lock.unlock();
  44. }
  45. }
  46. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

用Java写代码来解决生产者——消费者问题。

与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。在Java中怎么解决生产者——消费者问题,当然有很多解决方法,我已经分享了一种用阻塞队列实现的方法。有些时候他们甚至会问怎么实现哲学家进餐问题。

生产者、消费者有很多的实现方法: 
- 用wait() / notify()方法 
- 用Lock的多Condition方法 
- BlockingQueue阻塞队列方法

可以发现在上面实现阻塞队列题中,BlockingQueue的实现基本都用到了类似的实现,将BlockingQueue的实现方式稍微包装一下就成了一个生产者-消费者模式了。


  
  
  1. import java.util.Random;
  2. import java.util.concurrent.ArrayBlockingQueue;
  3. import java.util.concurrent.BlockingQueue;
  4. /**
  5. * 用阻塞队列快速实现生产者-消费者
  6. * @author xuexiaolei
  7. * @version 2017年11月01日
  8. */
  9. public class ProduceAndConsumer {
  10. public static void main(String[] args) {
  11. final BlockingQueue<Integer> list = new ArrayBlockingQueue<Integer>( 10);
  12. Procude procude = new Procude( list);
  13. Consumer consumer = new Consumer( list);
  14. procude.start();
  15. consumer.start();
  16. }
  17. static class Procude extends Thread{
  18. private final BlockingQueue<Integer> list;
  19. Procude(BlockingQueue<Integer> list) {
  20. this. list = list;
  21. }
  22. @Override public void run() {
  23. while( true){
  24. try {
  25. Integer take = list.take();
  26. System.out.println( "消费数据:" + take);
  27. // Thread.sleep(1000);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }
  34. static class Consumer extends Thread{
  35. private final BlockingQueue<Integer> list;
  36. Consumer(BlockingQueue<Integer> list) {
  37. this. list = list;
  38. }
  39. @Override public void run() {
  40. while ( true){
  41. try {
  42. int i = new Random().nextInt( 100);
  43. list.put(i);
  44. System.out.println( "生产数据:" + i);
  45. Thread.sleep( 1000);
  46. } catch (InterruptedException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }
  51. }
  52. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

此处不再详细地写另外几种实现方式了:wait() / notify()方法、Lock的多Condition方法、信号量等,甚至可以考虑用CyclicBarrier、CountDownLatch也可以实现生产者-消费者的,难易程度、效率不一样罢了。

用Java写一个会导致死锁的程序,你将怎么解决?

这是我最喜欢的Java线程面试问题,因为即使死锁问题在写多线程并发程序时非常普遍,但是很多侯选者并不能写deadlock free code(无死锁代码?),他们很挣扎。只要告诉他们,你有N个资源和N个线程,并且你需要所有的资源来完成一个操作。为了简单这里的n可以替换为2,越大的数据会使问题看起来更复杂。通过避免Java中的死锁来得到关于死锁的更多信息。


  
  
  1. /**
  2. * 简单死锁程序
  3. * lockA、lockB分别是两个资源,线程A、B必须同是拿到才能工作
  4. * 但A线程先拿lockA、再拿lockB
  5. * 线程先拿lockB、再拿lockA
  6. * @author xuexiaolei
  7. * @version 2017年11月01日
  8. */
  9. public class SimpleDeadLock {
  10. public static void main(String[] args) {
  11. Object lockA = new Object();
  12. Object lockB = new Object();
  13. A a = new A(lockA, lockB);
  14. B b = new B(lockA, lockB);
  15. a.start();
  16. b.start();
  17. }
  18. static class A extends Thread{
  19. private final Object lockA;
  20. private final Object lockB;
  21. A(Object lockA, Object lockB) {
  22. this.lockA = lockA;
  23. this.lockB = lockB;
  24. }
  25. @Override public void run() {
  26. synchronized (lockA){
  27. try {
  28. Thread.sleep( 1000);
  29. synchronized (lockB){
  30. System.out.println( "Hello A");
  31. }
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }
  37. }
  38. static class B extends Thread{
  39. private final Object lockA;
  40. private final Object lockB;
  41. B(Object lockA, Object lockB) {
  42. this.lockA = lockA;
  43. this.lockB = lockB;
  44. }
  45. @Override public void run() {
  46. synchronized (lockB){
  47. try {
  48. Thread.sleep( 1000);
  49. synchronized (lockA){
  50. System.out.println( "Hello B");
  51. }
  52. } catch (InterruptedException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56. }
  57. }
  58. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

产生死锁的四个必要条件: 
- 互斥条件:一个资源每次只能被一个进程使用。 
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免死锁? 
- 从死锁的四个必要条件来看,破坏其中的任意一个条件就可以避免死锁。但互斥条件是由资源本身决定的,不剥夺条件一般无法破坏,要实现的话得自己写更多的逻辑。 
- 避免无限期的等待:用Lock.tryLock(),wait/notify等方法写出请求一定时间后,放弃已经拥有的锁的程序。 
- 注意锁的顺序:以固定的顺序获取锁,可以避免死锁。 
- 开放调用:即只对有请求的进行封锁。你应当只想你要运行的资源获取封锁,比如在上述程序中我在封锁的完全的对象资源。但是如果我们只对它所属领域中的一个感兴趣,那我们应当封锁住那个特殊的领域而并非完全的对象。 
- 最后,如果能避免使用多个锁,甚至写出无锁的线程安全程序是再好不过了。

什么是原子操作,Java中的原子操作是什么?

非常简单的java线程面试问题,接下来的问题是你是否需要同步一个原子操作。

原子操作是不可分割的操作,一个原子操作中间是不会被其他线程打断的,所以不需要同步一个原子操作。 
多个原子操作合并起来后就不是一个原子操作了,就需要同步了。 
i++不是一个原子操作,它包含 读取-修改-写入 操作,在多线程状态下是不安全的。 
另外,java内存模型允许将64位的读操作或写操作分解为2个32位的操作,所以对long和double类型的单次读写操作并不是原子的,注意使用volitile使他们成为原子操作。

Java中的volatile关键是什么作用?怎样使用它?在Java中它跟synchronized方法有什么不同?

自从Java 5和Java内存模型改变以后,基于volatile关键字的线程问题越来越流行。应该准备好回答关于volatile变量怎样在并发环境中确保可见性。

volatile关键字的作用是:保证变量的可见性。 
在java内存结构中,每个线程都是有自己独立的内存空间(此处指的线程栈)。当需要对一个共享变量操作时,线程会将这个数据从主存空间复制到自己的独立空间内进行操作,然后在某个时刻将修改后的值刷新到主存空间。这个中间时间就会发生许多奇奇怪怪的线程安全问题了,volatile就出来了,它保证读取数据时只从主存空间读取,修改数据直接修改到主存空间中去,这样就保证了这个变量对多个操作线程的可见性了。换句话说,被volatile修饰的变量,能保证该变量的 单次读或者单次写 操作是原子的。

但是线程安全是两方面需要的 原子性(指的是多条操作)和可见性。volatile只能保证可见性,synchronized是两个均保证的。 
volatile轻量级,只能修饰变量;synchronized重量级,还可修饰方法。 
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。

什么是竞争条件(race condition)?你怎样发现和解决的?

这是一道出现在多线程面试的高级阶段的问题。大多数的面试官会问最近你遇到的竞争条件,以及你是怎么解决的。有些时间他们会写简单的代码,然后让你检测出代码的竞争条件。可以参考我之前发布的关于Java竞争条件的文章。在我看来这是最好的java线程面试问题之一,它可以确切的检测候选者解决竞争条件的经验。关于这方面最好的书是《java并发编程实战》。

竞争条件,在《java并发编程实战》叫做竞态条件:指设备或系统出现不恰当的执行时序,而得到不正确的结果。

下面是个最简单的例子,是一个单例模式实现的错误示范:


  
  
  1. @NotThreadSafe
  2. public class LazyInitRace {
  3. private ExpensiveObject instance = null;
  4. public ExpensiveObject getInstance () {
  5. if (instance == null)
  6. instance = new ExpensiveObject();
  7. return instance;
  8. }
  9. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在上述例子中,表现一种很常见的竞态条件类型:“先检查后执行”。根据某个检查结果来执行进一步的操作,但很有可能这个检查结果是失效的!还有很常见的竞态条件“读取-修改-写入”三连,在多线程条件下,三个小操作并不一定会放在一起执行的。

如何对待竞态条件? 
首先,警惕复合操作,当多个原子操作合在一起的时候,并不一定仍然是一个原子操作,此时需要用同步的手段来保证原子性。 
另外,使用本身是线程安全的类,这样在很大程度上避免了未知的风险。

你将如何使用thread dump?你将如何分析Thread dump?

在UNIX中你可以使用kill -3,然后thread dump将会打印日志,在windows中你可以使用”CTRL+Break”。非常简单和专业的线程面试问题,但是如果他问你怎样分析它,就会很棘手。

SIGQUIT(kill -3 pid)用来打印Java进程trace,并不会影响程序运行,不用担心他把程序杀死了;SIGUSR1(kill -10 pid)可触发进程进行一次强制GC。

java线程的状态转换介绍

后续分析要用到,所以此处穿插一下这个点: 
java线程的状态转换

  • 新建状态(New) 
    用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。
  • 就绪状态(Runnable) 
    当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。
  • 运行状态(Running) 
    处于这个状态的线程占用CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。
  • 阻塞状态(Blocked) 
    阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。 
    阻塞状态可分为以下3种: 
    1. 位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
    2. 位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
    3. 其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。
  • 死亡状态(Dead) 
    当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。

我们运行之前的那个死锁代码SimpleDeadLock.java,然后尝试输出信息(/*这是注释,作者自己加的*/):


  
  
  1. /* 时间,jvm信息 */
  2. 2017 - 11 - 01 17: 36: 28
  3. Full thread dump Java HotSpot(TM) 64-Bit Server VM ( 25.144-b01 mixed mode):
  4. /* 线程名称:DestroyJavaVM
  5. 编号:#13
  6. 优先级:5
  7. 系统优先级:0
  8. jvm内部线程id:0x0000000001c88800
  9. 对应系统线程id(NativeThread ID):0x1c18
  10. 线程状态: waiting on condition [0x0000000000000000] (等待某个条件)
  11. 线程详细状态:java.lang.Thread.State: RUNNABLE 及之后所有*/
  12. "DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000001c88800 nid=0x1c18 waiting on condition [0x0000000000000000]
  13. java .lang .Thread .State: RUNNABLE
  14. "Thread-1" #12 prio=5 os_prio=0 tid=0x0000000018d49000 nid=0x17b8 waiting for monitor entry [0x0000000019d7f000]
  15. /* 线程状态:阻塞(在对象同步上)
  16. 代码位置:at com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:<span class="hljs-number">56</span>)</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"> 等待锁:<span class="hljs-number">0x00000000d629b4d8</span> </span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment"> 已经获得锁:<span class="hljs-number">0x00000000d629b4e8</span>*/</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: BLOCKED (<span class="hljs-keyword">on</span> <span class="hljs-built_in">object</span> monitor)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.leo</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.interview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SimpleDeadLock</span>$B.run(SimpleDeadLock.java:56)
  17. - waiting to lock < 0x00000000d629b4d8> (a java .lang .Object)
  18. - locked < 0x00000000d629b4e8> (a java .lang .Object)
  19. "Thread-0" #11 prio=5 os_prio=0 tid=0x0000000018d44000 nid=0x1ebc waiting for monitor entry [0x000000001907f000]
  20. java .lang .Thread .State: BLOCKED ( on object monitor)
  21. at com .leo .interview .SimpleDeadLock$A<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(SimpleDeadLock<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">34</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="29"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">to</span> lock &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4e8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="30"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4d8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="31"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="32"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Service Thread"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#10 daemon prio=9 os_prio=0 tid=0x0000000018ca5000 nid=0x1264 runnable [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="33"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="34"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="35"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C1 CompilerThread2"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#9 daemon prio=9 os_prio=2 tid=0x0000000018c46000 nid=0xb8c waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="36"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="37"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="38"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C2 CompilerThread1"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#8 daemon prio=9 os_prio=2 tid=0x0000000018be4800 nid=0x1db4 waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="39"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="40"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="41"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"C2 CompilerThread0"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#7 daemon prio=9 os_prio=2 tid=0x0000000018be3800 nid=0x810 waiting on condition [0x0000000000000000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="42"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="43"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="44"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Monitor Ctrl-Break"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#6 daemon prio=5 os_prio=0 tid=0x0000000018bcc800 nid=0x1c24 runnable [0x00000000193ce000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="45"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: RUNNABLE</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="46"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.socketRead</span>0(Native Method)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="47"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.socketRead</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">116</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="48"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">171</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="49"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.net</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SocketInputStream</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(SocketInputStream<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">141</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="50"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readBytes</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">284</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="51"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.implRead</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">326</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="52"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at sun<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nio</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cs</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StreamDecoder</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(StreamDecoder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">178</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="53"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d632b928</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="54"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.read</span>(InputStreamReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">184</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="55"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.fill</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">161</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="56"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readLine</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">324</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="57"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d632b928</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.InputStreamReader</span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="58"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.io</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BufferedReader</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.readLine</span>(BufferedReader<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">389</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="59"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.intellij</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.rt</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.execution</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.application</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.AppMainV</span>2$ 1 .run(AppMainV2 .java: 64)
  22. "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000017781800 nid=0x524 runnable [0x0000000000000000]
  23. java .lang .Thread .State: RUNNABLE
  24. "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001778f800 nid=0x1b08 waiting on condition [0x0000000000000000]
  25. java .lang .Thread .State: RUNNABLE
  26. "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001776a800 nid=0xdac in Object.wait() [0x0000000018b6f000]
  27. java .lang .Thread .State: WAITING ( on object monitor)
  28. at java .lang .Object .wait(Native Method)
  29. - waiting on < 0x00000000d6108ec8> (a java .lang .ref .ReferenceQueue$Lock)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="71"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ReferenceQueue</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.remove</span>(ReferenceQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">143</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="72"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d6108ec8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ReferenceQueue</span>$Lock)
  30. at java .lang .ref .ReferenceQueue .remove(ReferenceQueue .java: 164)
  31. at java .lang .ref .Finalizer$FinalizerThread<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(Finalizer<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">209</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="75"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="76"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Reference Handler"</span></span> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><span class="hljs-meta">#2 daemon prio=10 os_prio=2 tid=0x0000000017723800 nid=0x1670 in Object.wait() [0x00000000189ef000]</span></span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="77"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Thread</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.State</span>: WAITING (<span class="hljs-keyword">on</span> <span class="hljs-built_in">object</span> monitor)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="78"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.wait</span>(Native Method)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="79"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">on</span> &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d6106b68</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Reference</span>$Lock)
  32. at java .lang .Object .wait( Object .java: 502)
  33. at java .lang .ref .Reference .tryHandlePending(Reference .java: 191)
  34. - locked < 0x00000000d6106b68> (a java .lang .ref .Reference$Lock)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="83"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ref</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Reference</span>$ReferenceHandler .run(Reference .java: 153)
  35. "VM Thread" os_prio= 2 tid= 0x000000001771b800 nid= 0x604 runnable
  36. "GC task thread#0 (ParallelGC)" os_prio= 0 tid= 0x0000000001c9d800 nid= 0x9f0 runnable
  37. "GC task thread#1 (ParallelGC)" os_prio= 0 tid= 0x0000000001c9f000 nid= 0x154c runnable
  38. "GC task thread#2 (ParallelGC)" os_prio= 0 tid= 0x0000000001ca0800 nid= 0xcd0 runnable
  39. "GC task thread#3 (ParallelGC)" os_prio= 0 tid= 0x0000000001ca2000 nid= 0x1e58 runnable
  40. "VM Periodic Task Thread" os_prio= 2 tid= 0x0000000018c5a000 nid= 0x1b58 waiting on condition
  41. JNI global references: 33
  42. /* 此处可以看待死锁的相关信息! */
  43. Found one Java-level deadlock:
  44. =============================
  45. "Thread-1":
  46. waiting to lock monitor 0x0000000017729fc8 ( object 0x00000000d629b4d8, a java .lang .Object),
  47. which is held by "Thread-0"
  48. "Thread-0":
  49. waiting to lock monitor 0x0000000017727738 ( object 0x00000000d629b4e8, a java .lang .Object),
  50. which is held by "Thread-1"
  51. Java stack information for the threads listed above:
  52. ===================================================
  53. "Thread-1":
  54. at com .leo .interview .SimpleDeadLock$B<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(SimpleDeadLock<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.java</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">56</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="114"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - waiting <span class="hljs-keyword">to</span> lock &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4d8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="115"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> - locked &lt;<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;"><span class="hljs-number">0x00000000d629b4e8</span></span>&gt; (a java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lang</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.<span class="hljs-built_in">Object</span></span>)</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="116"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"><span class="hljs-string">"Thread-0"</span></span>:</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="117"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> at <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.leo</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.interview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SimpleDeadLock</span>$A .run(SimpleDeadLock .java: 34)
  55. - waiting to lock < 0x00000000d629b4e8> (a java .lang .Object)
  56. - locked < 0x00000000d629b4d8> (a java .lang .Object)
  57. Found 1 deadlock.
  58. /* 内存使用状况,详情得看JVM方面的书 */
  59. Heap
  60. PSYoungGen total 37888K, used 4590K [ 0x00000000d6100000, 0x00000000d8b00000, 0x0000000100000000)
  61. eden space 32768K, 14% used [ 0x00000000d6100000, 0x00000000d657b968, 0x00000000d8100000)
  62. from space 5120K, 0% used [ 0x00000000d8600000, 0x00000000d8600000, 0x00000000d8b00000)
  63. to space 5120K, 0% used [ 0x00000000d8100000, 0x00000000d8100000, 0x00000000d8600000)
  64. ParOldGen total 86016K, used 0K [ 0x0000000082200000, 0x0000000087600000, 0x00000000d6100000)
  65. object space 86016K, 0% used [ 0x0000000082200000, 0x0000000082200000, 0x0000000087600000)
  66. Metaspace used 3474K, capacity 4500K, committed 4864K, reserved 1056768K
  67. class space used 382K, capacity 388K, committed 512K, reserved 1048576K
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132

为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

这是另一个非常经典的java多线程面试问题。这也是我刚开始写线程程序时候的困惑。现在这个问题通常在电话面试或者是在初中级Java面试的第一轮被问到。这个问题的回答应该是这样的,当你调用start()方法时你将创建新的线程,并且执行在run()方法里的代码。但是如果你直接调用run()方法,它不会创建新的线程也不会执行调用线程的代码。

简单点来说: 
new一个Thread,线程进入了新建状态;调用start()方法,线程进入了就绪状态,当分配到时间片后就可以开始运行了。 
start()会执行线程的相应准备工作,然后自动执行run()方法的内容。是真正的多线程工作。 
而直接执行run()方法,会把run方法当成一个mian线程下的普通方法去执行,并不会在某个线程中执行它,这并不是多线程工作。

Java中你怎样唤醒一个阻塞的线程?

这是个关于线程和阻塞的棘手的问题,它有很多解决方法。如果线程遇到了IO阻塞,我并且不认为有一种方法可以中止线程。如果线程因为调用wait()、sleep()、或者join()方法而导致的阻塞,你可以中断线程,并且通过抛出InterruptedException来唤醒它。我之前写的《How to deal with blocking methods in java》有很多关于处理线程阻塞的信息。

这个我们先简单粗暴地对某些阻塞方法进行分类: 
- 会抛出InterruptedException的方法:wait、sleep、join、Lock.lockInterruptibly等,针对这类方法,我们在线程内部处理好异常(要不完全内部处理,要不把这个异常抛出去),然后就可以实现唤醒。 
- 不会抛InterruptedException的方法:Socket的I/O,同步I/O,Lock.lock等。对于I/O类型,我们可以关闭他们底层的通道,比如Socket的I/O,关闭底层套接字,然后抛出异常处理就好了;比如同步I/O,关闭底层Channel然后处理异常。对于Lock.lock方法,我们可以改造成Lock.lockInterruptibly方法去实现。

在Java中CycliBarriar和CountdownLatch有什么区别?

这个线程问题主要用来检测你是否熟悉JDK5中的并发包。这两个的区别是CyclicBarrier可以重复使用已经通过的障碍,而CountdownLatch不能重复使用。

还要注意一点的区别: 
CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 
CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。 
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待,而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。 
从api上理解就是CountdownLatch有主要配合使用两个方法countDown()和await(),countDown()是做事的线程用的方法,await()是等待事情完成的线程用个方法,这两种线程是可以分开的(下面例子:CountdownLatchTest2),当然也可以是同一组线程(下面例子:CountdownLatchTest);CyclicBarrier只有一个方法await(),指的是做事线程必须大家同时等待,必须是同一组线程的工作。

CountdownLatch例子:


  
  
  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. /**
  5. * 线程都准备完成后一起执行的例子
  6. * @author xuexiaolei
  7. * @version 2017年11月02日
  8. */
  9. public class CountdownLatchTest {
  10. private final static int THREAD_NUM = 10;
  11. public static void main (String[] args) {
  12. CountDownLatch lock = new CountDownLatch(THREAD_NUM);
  13. ExecutorService exec = Executors.newCachedThreadPool();
  14. for ( int i = 0; i < THREAD_NUM; i++) {
  15. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  16. }
  17. exec.shutdown();
  18. }
  19. static class CountdownLatchTask implements Runnable{
  20. private final CountDownLatch lock;
  21. private final String threadName;
  22. CountdownLatchTask(CountDownLatch lock, String threadName) {
  23. this.lock = lock;
  24. this.threadName = threadName;
  25. }
  26. @Override public void run () {
  27. //循环多次是为了证明,CountdownLatch只会阻挡一次
  28. for ( int i = 0; i < 3; i++) {
  29. System.out.println(threadName + " 准备完成");
  30. lock.countDown();
  31. try {
  32. lock.await();
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. System.out.println(threadName + " 执行完成");
  37. }
  38. }
  39. }
  40. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

  
  
  1. import java.util.concurrent.CountDownLatch;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. /**
  5. * 各个线程执行完成后,主线程做总结性工作的例子
  6. * @author xuexiaolei
  7. * @version 2017年11月02日
  8. */
  9. public class CountdownLatchTest2 {
  10. private final static int THREAD_NUM = 10;
  11. public static void main (String[] args) {
  12. CountDownLatch lock = new CountDownLatch(THREAD_NUM);
  13. ExecutorService exec = Executors.newCachedThreadPool();
  14. for ( int i = 0; i < THREAD_NUM; i++) {
  15. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  16. }
  17. try {
  18. lock.await();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. System.out.println( "大家都执行完成了,做总结性工作");
  23. exec.shutdown();
  24. }
  25. static class CountdownLatchTask implements Runnable{
  26. private final CountDownLatch lock;
  27. private final String threadName;
  28. CountdownLatchTask(CountDownLatch lock, String threadName) {
  29. this.lock = lock;
  30. this.threadName = threadName;
  31. }
  32. @Override public void run () {
  33. System.out.println(threadName + " 执行完成");
  34. lock.countDown();
  35. }
  36. }
  37. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

CyclicBarrier例子:


  
  
  1. import java.util.concurrent.*;
  2. /**
  3. *
  4. * @author xuexiaolei
  5. * @version 2017年11月02日
  6. */
  7. public class CyclicBarrierTest {
  8. private final static int THREAD_NUM = 10;
  9. public static void main (String[] args) {
  10. CyclicBarrier lock = new CyclicBarrier(THREAD_NUM, new Runnable() {
  11. @Override public void run () {
  12. System.out.println( "大家都准备完成了");
  13. }
  14. });
  15. ExecutorService exec = Executors.newCachedThreadPool();
  16. for ( int i = 0; i < THREAD_NUM; i++) {
  17. exec.submit( new CountdownLatchTask(lock, "Thread-"+i));
  18. }
  19. exec.shutdown();
  20. }
  21. static class CountdownLatchTask implements Runnable{
  22. private final CyclicBarrier lock;
  23. private final String threadName;
  24. CountdownLatchTask(CyclicBarrier lock, String threadName) {
  25. this.lock = lock;
  26. this.threadName = threadName;
  27. }
  28. @Override public void run () {
  29. for ( int i = 0; i < 3; i++) {
  30. System.out.println(threadName + " 准备完成");
  31. try {
  32. lock.await();
  33. } catch (BrokenBarrierException e) {
  34. e.printStackTrace();
  35. } catch (InterruptedException e) {
  36. e.printStackTrace();
  37. }
  38. System.out.println(threadName + " 执行完成");
  39. }
  40. }
  41. }
  42. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

什么是不可变对象,它对写并发应用有什么帮助?

另一个多线程经典面试问题,并不直接跟线程有关,但间接帮助很多。这个java面试问题可以变的非常棘手,如果他要求你写一个不可变对象,或者问你为什么String是不可变的。

immutable Objects(不可变对象)就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对他们的改变都是产生了新的immutable的对象,而mutable Objects(可变对象)就是那些创建后,状态可以被改变的Objects.

如何在Java中写出Immutable的类? 
1. immutable对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象。 
2. immutable类的所有的属性都应该是final的。 
3. 对象必须被正确的创建,比如:对象引用在对象创建过程中不能泄露(leak)。 
4. 对象应该是final的,以此来限制子类继承父类,以避免子类改变了父类的immutable特性。 
5. 如果类中包含mutable类对象,那么返回给客户端的时候,返回该对象的一个拷贝,而不是该对象本身(该条可以归为第一条中的一个特例)

使用Immutable类的好处: 
1. Immutable对象是线程安全的,可以不用被synchronize就在并发环境中共享 
2.Immutable对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程间共享 
3. Immutable对象提高了程序的性能,因为它减少了synchroinzed的使用 
4. Immutable对象是可以被重复使用的,你可以将它们缓存起来重复使用,就像字符串字面量和整型数字一样。你可以使用静态工厂方法来提供类似于valueOf()这样的方法,它可以从缓存中返回一个已经存在的Immutable对象,而不是重新创建一个。


  
  
  1. /**
  2. * 不可变对象
  3. * @author xuexiaolei
  4. * @version 2017年11月03日
  5. */
  6. public class ImmutableObjectPerson {
  7. private final String name;
  8. private final String sex;
  9. public ImmutableObjectPerson (String name, String sex) {
  10. this.name = name;
  11. this.sex = sex;
  12. }
  13. public String getName () {
  14. return name;
  15. }
  16. public String getSex () {
  17. return sex;
  18. }
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

你在多线程环境中遇到的常见的问题是什么?你是怎么解决它的?

多线程和并发程序中常遇到的有Memory-interface、竞争条件、死锁、活锁和饥饿。问题是没有止境的,如果你弄错了,将很难发现和调试。这是大多数基于面试的,而不是基于实际应用的Java线程问题。

此类问题请大家面试的时候提前准备,方便交流,如果实在找不出来,可以想想自己平时解决问题的思路,总结下来告诉考官。

猜你喜欢

转载自blog.csdn.net/csdn331/article/details/81559894