繁体   English   中英

解释jstack跟踪以跟踪停滞的锁定

[英]Interpreting jstack trace to track down the stalled lock

我已经使用过Samurai,我可以看到没有死锁和几个线程在等待,但我似乎无法弄清楚究竟是哪个锁停止了这个过程。 谁能帮我吗?

我不是在寻找人们猜测我的问题是什么,更多关于如何改变代码以便更容易追踪问题的建议。 我通过我的第一次发送和接收然后程序停止它应该发送第二条消息。 我是多线程的新手,这是我第一次拉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

按要求添加代码Serial通信类

    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线程,每个线程包含一个包含一个位串的基因组。 这个基因组参考保存在candidateTest中,该候选测试只是RobotInterface的一个共享类,以及完成时发出信号的调用线程。

位串由RobotInterface使用TwoWaySerialCommTest发送到机器人。 机器人对其进行求值并返回一个适应函数,该函数由SerialReader解析为float。 然后将下一个String发送给机器人。

在第一个字符串返回到机器人并且正在发送第二个字符串后,将发生锁定。 我可以看到第一个String使它成为机器人,但第二个字符串没有。 输出如下 -

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

我的方法是消除明显不相关的线程。 对你来说,这可能是

  • 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可以检测死锁但不能检测到活锁)。

这是我对如何解决它的一般想法。 如果你想在某个地方发布代码,那么实际调试它/提供更多洞察人们可能会如何解决它是有帮助的。

祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM