2013-04-02 57 views
0

我用過Samurai,我可以看到沒有死鎖,有幾個線程正在等待,但我似乎無法確切知道哪個鎖正在拖延進程。誰能幫我嗎?解釋jstack trace追蹤失速的鎖

我不是在尋找人來猜測我的問題是什麼,更多關於如何改變代碼的建議,以便更容易地跟蹤問題。我通過我的第一次發送和接收,然後程序停止發送第二條消息。我是新來的多線程,這是我第一次拉jstack

2013-04-02 23:43:12 
Full thread dump OpenJDK Zero VM (22.0-b10 mixed mode): 

"Attach Listener" daemon prio=10 tid=0x0037c880 nid=0x105b waiting on condition  [0x00000000] 
java.lang.Thread.State: RUNNABLE 

"Thread-3" prio=10 tid=0x0037c488 nid=0x1041 waiting on condition [0xa7ddd000] 
java.lang.Thread.State: WAITING (parking) 
    at sun.misc.Unsafe.park(Native Method) 
    - parking to wait for <0xab770958> (a  java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.evaluate(RobotInterface.java:38) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.RobotInterface.run(RobotInterface.java:69) 
    at java.lang.Thread.run(Thread.java:722) 

"Thread-1" prio=10 tid=0x0036ff10 nid=0x1036 waiting on condition [0xa7f5d000] 
java.lang.Thread.State: WAITING (parking) 
    at sun.misc.Unsafe.park(Native Method) 
    - parking to wait for <0xab770940> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.TwoWaySerialCommTest$SerialWriter.run(TwoWaySerialCommTest.java:229) 
    at java.lang.Thread.run(Thread.java:722) 

"Thread-0" daemon prio=10 tid=0x0036a1e8 nid=0x1035 runnable [0xa80dd000] 
java.lang.Thread.State: RUNNABLE 
    at gnu.io.RXTXPort.eventLoop(Native Method) 
    at gnu.io.RXTXPort$MonitorThread.run(RXTXPort.java:1644) 

"Service Thread" daemon prio=10 tid=0x00253440 nid=0x102b runnable [0x00000000] 
java.lang.Thread.State: RUNNABLE 

"Signal Dispatcher" daemon prio=10 tid=0x00251988 nid=0x102a runnable [0x00000000] 
java.lang.Thread.State: RUNNABLE 

"Finalizer" daemon prio=10 tid=0x0020c880 nid=0x1029 in Object.wait() [0xa8ac1000] 
java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0xab718a88> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) 
    - locked <0xab718a88> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) 
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177) 

"Reference Handler" daemon prio=10 tid=0x00209f18 nid=0x1028 in Object.wait() [0xa8c41000] 
java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0xab718b10> (a java.lang.ref.Reference$Lock) 
    at java.lang.Object.wait(Object.java:503) 
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) 
    - locked <0xab718b10> (a java.lang.ref.Reference$Lock) 

"main" prio=10 tid=0x00180fa8 nid=0x1022 in Object.wait() [0xb6848000] 
java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0xa90716a8> (a org.dnsdojo.ryanhost.GA.MuPlusOne.CandidateTest) 
    at java.lang.Object.wait(Object.java:503) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.MuPlusOneAlgorithm.runOnBot(MuPlusOneAlgorithm.java:120) 
    - locked <0xa90716a8> (a org.dnsdojo.ryanhost.GA.MuPlusOne.CandidateTest) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.MuPlusOneAlgorithm.initialFitness(MuPlusOneAlgorithm.java:72) 
    - locked <0xab718bd0> (a org.dnsdojo.ryanhost.GA.MuPlusOne.MuPlusOneAlgorithm) 
    at org.dnsdojo.ryanhost.GA.MuPlusOne.MuPlusOneAlgorithm.main(MuPlusOneAlgorithm.java:138) 

"VM Thread" prio=10 tid=0x00204910 nid=0x1027 runnable 

"VM Periodic Task Thread" prio=10 tid=0x00255130 nid=0x102c waiting on condition 

JNI global references: 36 

添加代碼的要求 串行通信類

package org.dnsdojo.ryanhost.GA.MuPlusOne; 

    import gnu.io.CommPort; 
    import gnu.io.CommPortIdentifier; 
    import gnu.io.SerialPort; 
    import gnu.io.SerialPortEvent; 
    import gnu.io.SerialPortEventListener; 

    import java.io.IOException; 
    import java.io.InputStream; 
    import java.io.OutputStream; 

    /** 
    * This version of the TwoWaySerialComm example makes use of the 
    * SerialPortEventListener to avoid polling. 
    * 
    */ 
    public class TwoWaySerialComm 
    { 
     public TwoWaySerialComm() 
     { 
      super(); 
     } 

     void connect (String portName) throws Exception 
     { 
      listPorts(); 
      CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); 
      if (portIdentifier.isCurrentlyOwned()) 
      { 
       System.out.println("Error: Port is currently in use"); 
      } 
      else 
      { 
       CommPort commPort = portIdentifier.open(this.getClass().getName(),2000); 

       if (commPort instanceof SerialPort) 
       { 
        SerialPort serialPort = (SerialPort) commPort; 
        serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); 

        InputStream in = serialPort.getInputStream(); 
        OutputStream out = serialPort.getOutputStream(); 

        (new Thread(new SerialWriter(out))).start(); 

        serialPort.addEventListener(new SerialReader(in)); 
        serialPort.notifyOnDataAvailable(true); 

       } 
       else 
       { 
        System.out.println("Error: Only serial ports are handled by this example."); 
       } 
      } 
     } 

     static void listPorts() 
     { 
      java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers(); 
      while(portEnum.hasMoreElements()) 
      { 
        CommPortIdentifier portIdentifier = portEnum.nextElement(); 
        if(portIdentifier == null) 
        { 
          System.out.println("No ports"); 
        } 
        System.out.println("Available - " + portIdentifier.getName()); 
      } 
     } 

     /** 
     * Handles the input coming from the serial port. A new line character 
     * is treated as the end of a block in this example. 
     */ 
     public static class SerialReader implements SerialPortEventListener 
     { 
      private InputStream in; 
      private byte[] buffer = new byte[1024]; 

      public SerialReader (InputStream in) 
      { 
       this.in = in; 
      } 

      public void serialEvent(SerialPortEvent arg0) { 
       int data; 

       try 
       { 
        int len = 0; 
        while ((data = in.read()) > -1) 
        { 
         if (data == '\n') { 
          break; 
         } 
         buffer[len++] = (byte) data; 
        } 
        System.out.print(new String(buffer,0,len)); 
       } 
       catch (IOException e) 
       { 
        e.printStackTrace(); 
        System.exit(-1); 
       } 
      } 

     } 

     /** */ 
     public static class SerialWriter implements Runnable 
     { 
      OutputStream out; 

      public SerialWriter (OutputStream out) 
      { 
       this.out = out; 
      } 

      public void run() 
      { 
       try 
       { 
        int c = 0; 
        while ((c = System.in.read()) > -1) 
        { 
         this.out.write(c); 
        } 
       } 
       catch (IOException e) 
       { 
        e.printStackTrace(); 
        System.exit(-1); 
       } 
      } 
     } 



     public static void main (String[] args) 
     { 
      try 
      { 
       (new TwoWaySerialComm()).connect("/dev/ttyS82"); 
      } 
      catch (Exception e) 
      { 
       TwoWaySerialComm.listPorts(); 
       e.printStackTrace(); 
      } 
     } 


    } 

的RobotInterface類

package org.dnsdojo.ryanhost.GA.MuPlusOne; 

import org.apache.log4j.Logger; 
import org.apache.log4j.PropertyConfigurator; 

public class RobotInterface implements Runnable 
{ 
    // create a serial connection 
    // transmit a string and check for response 
    // wait for evaluation 
    // take evaluation 
    private CandidateTest candidate; 
    private TwoWaySerialCommTest serialConnection; 
    //private Random rng = new Random(); 

    protected static Logger logger = Logger.getLogger("Thread" + Thread.currentThread().getName()); 

    public RobotInterface(CandidateTest test, TwoWaySerialCommTest serialConnection) 
    { 
      this.candidate = test; 
      this.serialConnection = serialConnection; 
      PropertyConfigurator.configure("log4j.properties"); 
    } 

    public void evaluate (Genome genome) 
    { 
      //send to robot and return fitness 
      //genome.setFitness(rng.nextDouble()); 
      logger.debug("fitness is " + genome.getFitness()); 

        try 
     { 
          String s = candidate.getCandidate().toString(); 
          System.out.println(s); 
          TwoWaySerialCommTest.lock.lock(); 
          System.out.println(s); 
      serialConnection.put(s); 
      TwoWaySerialCommTest.inputAvailable.await(); 
      try 
      { 
        candidate.getCandidate().setFitness(Float.parseFloat(serialConnection.take())); 
      } 
      catch(Exception e) 
      { 
        e.printStackTrace(); 
      } 


     } 
     catch (Exception e) 
     { 
      TwoWaySerialCommTest.listPorts(); 
      e.printStackTrace(); 
     } 
        finally 
        { 
          TwoWaySerialCommTest.lock.unlock(); 
        } 
    } 




    public void run() 
    { 
      logger.debug("entering run of Robot Interface"); 
      logger.debug("Send Genome via serial and wait for a response"); 
      Genome testSubject = candidate.getCandidate(); 
      evaluate(testSubject); 
      candidate.finished(); 
    } 
} 

總結執行 - 我有一個for循環創建RobotInterface線程,每個線程都包含一個位串。該基因組引用保存在候選測試中,該候選測試僅僅是RobotInterface的共享類和調用線程在完成時發出信號。

使用TwoWaySerialCommTest通過RobotInterface將位串發送給機器人。機器人對其進行評估並返回一個適應函數,該函數由SerialReader解析爲一個浮點數。下一個字符串然後被髮送給機器人。

鎖定發生在第一個字符串返回到機器人併發送第二個字符串之後。我可以看到第一個字符串將其傳遞給機器人,但第二個字符串沒有。輸出如下 -

initialFitness method 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 
5436 [main] DEBUG org.dnsdojo.ryanhost.GA.MuPlusOne.GeneticAlgorithm - Testing candidate 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 
5853 [Thread-2] DEBUG Threadmain - entering run of Robot Interface 
5869 [Thread-2] DEBUG Threadmain - Send Genome via serial and wait for a response 
5881 [Thread-2] DEBUG Threadmain - fitness is 0.0 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 
10 
Output buffer after put 
1101010101111111001100000101011100110000100001111111001000001001101101000011100101011000000100000000110110001110 

Buffer isn't empty 

initialFitness method 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 
16593 [main] DEBUG org.dnsdojo.ryanhost.GA.MuPlusOne.GeneticAlgorithm - Testing candidate 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 
16944 [Thread-3] DEBUG Threadmain - entering run of Robot Interface 
16953 [Thread-3] DEBUG Threadmain - Send Genome via serial and wait for a response 
16964 [Thread-3] DEBUG Threadmain - fitness is 0.0 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 
10 
Output buffer after put 
1110110101110000001100101100110001001010010101011110001101010010100100111011111000011101110000001110100111001111 

Buffer isn't empty 

回答

2

我的方法是消除明顯不相關的線程。對你來說,這可能是

  • Attach Listener
  • Service Thread
  • Signal Dispatcher
  • Finalizer
  • Reference Handler
  • VM Thread
  • VM Periodic Task Thread

這些是VM管理的線程,即,您沒有明確或隱式地創建它們。

那留下Thread-xMain線程。

查看堆棧跟蹤,根據您對代碼的瞭解,可以推斷出爲什麼事情是WAITING。例如,看起來隊列正在等待Condition被滿足;

parking to wait for <0xab770958> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) 

Conditionssignal版醒來,所以你可能會想,爲什麼沒有被髮送signal消息。因爲這個條件包含在隊列實現中,所以問題不大可能是您忘記撥打signal。然而,你可能忘記了打電話給它的東西?或無意中設置了一個條件從未滿足的情況?

所以我會研究事件的流程,以確保任何被鎖定的內容被解鎖或者任何可能導致活鎖的情況(請記住,JVM/samauri可以檢測到死鎖但不能活鎖)。

這是我對如何解決它的一般想法。如果你想在其他地方發佈代碼,那麼在實際調試它時會很有幫助,或者提供更多的信息來幫助人們解決這個問題。

祝你好運!

+0

謝謝,我已經添加了代碼的問題,因爲你可以看到它是相當一線的球:(我正在通過它自己在此刻根據你的一般答案,這是相當有幫助 – SMC

+0

我是當我從串口讀取時,認爲我的問題在RobotInterface類中,也許鎖在雙嘗試/捕獲中沒有被正確釋放? – SMC

+0

因此,在我將這個頭撞了很長時間之後,事實證明問題與串行連接沒有確認和響應某些字符串有關,但是您的建議確實幫助我排除了線程問題,所以感謝上百萬 – SMC