2017-05-07 59 views
0

你能描述一下在多线程环境下,下面的代码工作不正确吗?我从https://www.javacodegeeks.com/2014/11/multithreading-concurrency-interview-questions-answers.html获取了代码。说明说2个线程可能会一个接一个地进入第二个同步块。这怎么会发生?有两个同步块是什么关系?2个线程如何能够同时访问同步块?

public Integer getNextInt() { 
    Integer retVal = null; 
    synchronized (queue) { 
     try { 
      while (queue.isEmpty()) { 
       queue.wait(); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    synchronized (queue) { 
     retVal = queue.poll(); 
     if (retVal == null) { 
      System.err.println("retVal is null"); 
      throw new IllegalStateException(); 
     } 
    } 
    return retVal; 
} 

回答

1

这很简单 - 第一个同步块(S1)让一个线程等待,直到队列变为非空。第二个同步块(S2)使单个线程从队列中取出一个项目。

  1. 线程1进入S1。
  2. 线程1存在S1 - >队列不为空
  3. 线程2进入S1
  4. 线程2存在S1 - >队列仍然是不为空
  5. 线程1进入S2 - >需要一个项目从队列和它变空
  6. 线程1存在S2
  7. 线程2进入S2->尝试从队列中取一个元素,但它是空的 - >抛出异常。

正如你所看到的,只有一个线程按预期进入一个同步块,但是这并不能保证正确的同步。

0

使用同步块的整点是创建必须一起执行的“事务”周围的代码段; 没有另一个线程进入“之间”的机会。

你的例子有两个块;并且很可能第一个线程离开第一个程序段;但在第一个线程可以进入第二个块之前,第二个线程将会启动。

这就是这一切。

0

queue.wait()释放锁,该锁应用于同步块。换句话说,当达到queue.wait()时,其他线程可以自由进入同步块。下面我包含一个工作示例,其中5个线程同时进入同一个同步块。您可以检查此代码以获得一个感觉wait()和notiy()/ notifyAll()方法的工作原理:

public class Main { 
    static Object lock = new Object(); 
    public static void main(String args[]) throws InterruptedException { 

     Runnable r =() -> { 
      System.out.println(" ThreadID: " + Thread.currentThread().getId() + " has started"); 
      synchronizedBlockExecution(); 
     }; 

     for (int i = 0; i < 5; i++) { 
      Thread t = new Thread(r); 
      t.start(); 
     } 

     Thread.sleep(1000); 
     System.out.println("------all threads are notifed to stop waiting!---------"); 
     synchronized (lock) { 
      lock.notifyAll(); 
     } 

    } 

    public static void synchronizedBlockExecution() { 
      System.out.println("Thread: " + Thread.currentThread().getId() + " is entering synchronized block"); 
      synchronized (lock) { 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      System.out.println("Thread: " + Thread.currentThread().getId() + " has left synchronized block"); 
    } 
} 
0

T1进入S1
T1存在S1
T2等待T1从S1完成
T1完成并进入S2
S1对于T2是空闲的
T2进入S1
以这种方式,T1和T2一次可以在两个不同的同步块中。这会提高性能。程序员应该写同步块而不是方法,因为它允许两个线程同时在两个单独的块中工作。