并发主题

多线程常见面试题

  1. 你有线程T1,T2和T3,你将如何确保线程T2运行后T1后,T3运行在T2线程后?
    它可以实现通过加入Thread类的join方法。

  2. Java中新锁接口相比synchronized有什么好处?要实现一个高性能缓存,它允许多个读,但单一的写,以保持完整性,你将如何实施呢?
    新锁接口提供了分离的两个单独读和写的锁,这样能够使用ConcurrentHashMap等高性能数据结构来实现高性能缓存。

  3. Java中wait和sleep区别?
    wait会释放锁或监视者,但是sleep不会释放任何锁和监视者,wait用来做线程内部通讯,而sleep用来引入一个执行过程中的暂停。

  4. 写代码实现堵塞队列和Producer/consumer模式?

    public class ProducerConsumerPattern {

        public static void main(String args[]){
     
         //Creating shared object
         BlockingQueue sharedQueue = new LinkedBlockingQueue();
     
         //Creating Producer and Consumer Thread
         Thread prodThread = new Thread(new Producer(sharedQueue));
         Thread consThread = new Thread(new Consumer(sharedQueue));

         //Starting producer and Consumer thread
         prodThread.start();
         consThread.start();
        }
     
    }

    //Producer Class in java
    class Producer implements Runnable {

        private final BlockingQueue sharedQueue;

        public Producer(BlockingQueue sharedQueue) {
            this.sharedQueue = sharedQueue;
        }

        @Override
        public void run() {
            for(int i=0; i<10; i++){
                try {
                    System.out.println("Produced: " + i);
                    sharedQueue.put(i);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

    }

    //Consumer Class in Java
    class Consumer implements Runnable{

        private final BlockingQueue sharedQueue;

        public Consumer (BlockingQueue sharedQueue) {
            this.sharedQueue = sharedQueue;
        }
     
        @Override
        public void run() {
            while(true){
                try {
                    System.out.println("Consumed: "+ sharedQueue.take());
                } catch (InterruptedException ex) {
                    Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
     
     
    }

    Output:
    Produced: 0
    Produced: 1
    Consumed: 0
    Produced: 2
    Consumed: 1
    Produced: 3
    Consumed: 2
    Produced: 4
    Consumed: 3
    Produced: 5
    Consumed: 4
    Produced: 6
    Consumed: 5
    Produced: 7
    Consumed: 6
    Produced: 8
    Consumed: 7
    Produced: 9
    Consumed: 8
    Consumed: 9

  5. 写段代码演示线程死锁,如何解决死锁?
    见:死锁详解研究

    public void method1(){
    synchronized(String.class){
    System.out.println("Aquired lock on String.class object");

    synchronized (Integer.class) {
    System.out.println("Aquired lock on Integer.class object");
    }
    }
    }

    public void method2(){
    synchronized(Integer.class){
    System.out.println("Aquired lock on Integer.class object");

    synchronized (String.class) {
    System.out.println("Aquired lock on String.class object");
    }
    }
    }

    解决方式,调整调用顺序:

    public void method1(){
    synchronized(Integer.class){
    System.out.println("Aquired lock on Integer.class object");

    synchronized (String.class) {
    System.out.println("Aquired lock on String.class object");
    }
    }
    }

    public void method2(){
    synchronized(Integer.class){
    System.out.println("Aquired lock on Integer.class object");

    synchronized (String.class) {
    System.out.println("Aquired lock on String.class object");
    }
    }
    }

  6. 什么是原子操作?
    原子操作能保证线程安全,非原子操作就是线程不安全,通过使用锁或其他非堵塞方式实现某个时间只能有一个线程操作同一资源。

  7. volatile是什么?
    volatile关键字用来指示Java编译器和线程,不要缓存这个变量的值,总是从主内存读取。如果你想分享其中的任何变量进行读写操作是原子的。
    详细见:JVM内存模型


  8. 什么是竞争条件,如何发现竞争条件?
    如果两个线程同时访问同一个资源容易发生竞争情况,如果两个线程试图在同一时间递增计数,如果他们读相同的值,因为交错,一个线程来读操作而另一个线程更新操作,其中一个线程的操作结果将会丢失,当一个线程覆盖由其他线程完成的增量。原子操作并不有关操作的次序,与竞争条件无关。
    见:什么使得并行编程变得很难?

  9. 什么是堵塞的方法?如何唤醒堵塞的线程?
    如果堵塞在wait(), sleep() or join(),使用InterruptedException.可以中断线程。
    但是大部分Java IO是堵塞的,如:

    public class BlcokingCallTest {

        public static void main(String args[]) throws FileNotFoundException, IOException  {
          System.out.println("Calling blocking method in Java");
          int input = System.in.read();
          System.out.println("Blocking method is finished");
        } 
    }
    这种情况只能改变编程风格,比如使用EDA等方式。

  10. CyclicBarriar 和 CountdownLatch的区别是什么?
    这两个允许线程彼此等待在barrier,CyclicBarrier 能重用,一旦计数达到零,你调用reset()方法可以复位到初始状态。而 CountdownLatch不能,适合使用在系统启动时。
    代码如下:

    public class CyclicBarrierExample {

    //Runnable task for each thread
    private static class Task implements Runnable {

    private CyclicBarrier barrier;

    public Task(CyclicBarrier barrier) {
    this.barrier = barrier;
    }

    @Override
    public void run() {
    try {
    System.out.println(Thread.currentThread().getName() + " is waiting on barrier");
    barrier.await();
    System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
    } catch (InterruptedException ex) {
    Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);
    } catch (BrokenBarrierException ex) {
    Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }

    public static void main (String args[]) {

    //creating CyclicBarrier with 3 parties i.e. 3 Threads needs to call await()
    final CyclicBarrier cb = new CyclicBarrier(3, new Runnable(){
    @Override
    public void run(){
    //This task will be executed once all thread reaches barrier
    System.out.println("All parties are arrived at barrier, lets play");
    }
    });

    //starting each of thread
    Thread t1 = new Thread(new Task(cb), "Thread 1");
    Thread t2 = new Thread(new Task(cb), "Thread 2");
    Thread t3 = new Thread(new Task(cb), "Thread 3");

    t1.start();
    t2.start();
    t3.start();

    }
    }

    输出:
    Thread 1 is waiting on barrier
    Thread 3 is waiting on barrier
    Thread 2 is waiting on barrier
    All parties are arrived at barrier, lets play
    Thread 3 has crossed the barrier
    Thread 1 has crossed the barrier
    Thread 2 has crossed the barrier

  11. 什么是不可变性?
    见:不可变真的意味线程安全?


Java企业系列面试题(线程篇)

java多线程

Java同步或锁

Java性能调优