2015-08-13 41 views
2

我是JAVA新手,在JAVA中學習多線程。這是我的代碼片段。瞭解JAVA中的同步方法

import java.util.*; 
import java.lang.*; 
import java.io.*; 

class Manager { 
    static final int MAXQUEUE = 5; 
    private Vector messages = new Vector(); 

    public synchronized void putMessage() throws InterruptedException { 
     while (messages.size() == MAXQUEUE) { 
      System.out.println("waiting for space in queue "); 
      wait(); 
     } 
     messages.addElement(new java.util.Date().toString()); 
     System.out.println("created a new message and message count is " + messages.size()); 
     notify(); 
    } 

    public synchronized String getMessage() throws InterruptedException { 
     notify(); 
     while (messages.size() == 0) { 
      System.out.println("queue is empty "); 
      wait(); 
     } 
     String message = (String) messages.firstElement(); 
     messages.removeElement(message); 
     System.out.println("removed a message and message count is " + messages.size()); 
     return message; 
    } 
} 

class Producer extends Thread { 
    Manager myRef; 

    Producer(Manager ref) { 
     myRef = ref; 
    } 

    public void run() { 
     try { 
      while (true) { 
       myRef.putMessage(); 
       sleep(1000); 
      } 
     } catch (InterruptedException e) { 
     } 
    } 
} 

class Consumer extends Thread { 
    Manager myRef; 

    Consumer(Manager ref) { 
     myRef = ref; 
    } 

    public void run() { 
     try { 
      while (true) { 
       String message = myRef.getMessage(); 
       System.out.println("Got message: " + message); 
       sleep(2000); 
      } 
     } catch (InterruptedException e) { 
     } 
    } 

    public static void main(String args[]) { 
     Manager ref = new Manager(); 
     Producer producer = new Producer(ref); 
     producer.start(); 
     new Consumer(ref).start(); 
    } 
} 

什麼我期待

  1. 首先我的生產者線程將管理對象的鎖的控制。它會調用putMessage(),直到count爲5並釋放鎖。
  2. 現在消費者線程將取得鎖定並開始讀取消息,直到列表爲空,然後它將釋放鎖定。 這個序列將繼續。

但是,發生了什麼

created a new message and message count is 1 
removed a message and message count is 0 
Got message: Thu Aug 13 07:26:45 GMT 2015 
created a new message and message count is 1 
removed a message and message count is 0 
Got message: Thu Aug 13 07:26:46 GMT 2015 
and so on..... 

正如你看到的,我的消費線程能夠調用readMessage(),即使經理對象的鎖是生產者線程這是執行putMessage()。如果一個線程正在執行實例方法,那麼其他線程如何能夠調用另一個實例方法?

請糾正我的理解。

+0

載體???????? – aviad

+0

嘗試閱讀關於多線程如何工作的一些閱讀。你在方法上同步,但這不會阻止你的消息對象的問題。 – aviad

+0

我在輸出中看不到問題。消息被添加,然後刪除,然後添加另一條消息,然後刪除。是什麼讓你認爲兩個線程同時運行同步方法? – immibis

回答

1

步驟明智每個線程的執行:

  1. 生產者線程啓動:

    run()方法被調用它調用PUTMESSAGE方法

    PUTMESSAGE():它是同步的,因此作爲生產者線程的當前線程獲取當前管理器對象的鎖定。現在在此期間沒有其他線程可以在同一個對象上調用另一個同步方法。由於消息的大小爲< MAXQUEUE(5),因爲它只是第一次插入它將元素插入向量消息中。然後它調用notify()來發信號通知任何其他正在等待的線程準備重新獲得鎖。請注意,調用notify()本身不會釋放鎖。如果您願意,可以在調用notify()之後繼續做些事情。 Notify()只是等待線程準備排隊獲取鎖的信號。只有當同步函數退出或它調用wait()時纔會釋放鎖。

    線程睡眠1秒。

  2. 消費者線程開始:

    run()方法被調用它調用的getMessage()

    的getMessage():如上所述,將在類似的原理工作,以從載體如果提取的消息它不是空的。請注意,它在進入時首先調用notify()。這樣做是爲了在getMessage執行之後發出任何等待的生產者線程準備就緒的信號,以保證向量的大小小於MAXSIZE。再次如前所述,只需調用notify()不會釋放鎖。

    線程睡2秒鐘。

這兩個線程執行以平行的方式,併爲您的兩倍,只要生產者睡覺消費者,你會過一段時間後發現,緩衝區將得到填補,這是然後,當我們真正需要的等待並通知方法。

2

首先你的生產者Thread執行putMessage方法。他創建一個項目並將其添加到messages列表中。當putMessage完成並且創建了一個項目時,生產者線程進入睡眠狀態。

當消費者線程覺醒時,他可以自由地訪問getMessage方法並消費唯一的項目。然後消費者去睡覺。

此過程一直重複。正如你期望的那樣,synchronized關鍵字可以防止一個對象的任何同步方法可以並行執行。正如我所解釋的那樣,並沒有發生。線程只是在訪問方法時交替使用。每個方法調用只生成或消耗一個項目。

2

這是java多線程的正確行爲。

首先我的Producer線程將控制對象管理器 上的鎖定。它將調用putMessage(),直到count爲5,並且將釋放鎖。

我不知道,如果你寫的代碼這一行

It will call putMessage() until the count is 5 and will release the lock. 

因爲你的代碼說

 public synchronized void putMessage() throws InterruptedException { 
     // Check if messages list size is full. If full then wait for emptying 
     while (messages.size() == MAXQUEUE) { 
      System.out.println("waiting for space in queue "); 
      wait(); 
     } 
     // If not, add one element. Where have you written code for adding 5 elements at once. 
     messages.addElement(new java.util.Date().toString()); 
     System.out.println("created a new message and message count is " + messages.size()); 
     notify(); 
    } 

請檢查下面的鏈接。

https://community.oracle.com/thread/2293851

+0

我認爲通知不會釋放鎖。起初我有一個印象,即由於Producer正在調用putMessage(),Consumer將無法調用getMessage()。所以,putMessage()將繼續執行,直到count變爲5,然後它將移動到wait()。 –

+0

https://community.oracle.com/thread/2293851 –

+0

@KeshavSharma是的,你是對的。看到這個http://stackoverflow.com/questions/5999193/java-wait-notify-notifyall。請參閱我的答案瞭解更多詳情。 –