Java Thread

Links to the original text: http://www.cnblogs.com/riasky/p/3471472.html

This article has been kept in the draft box for a long time. Recently, some students in the company's technical community posted several articles sharing Java threads. They found that many concepts were not clear, so they took some time to continue to write this blog. This article focuses on JVM-level threading models and does not consider linking them to real operating system Thread models (due to limited space, this article will not introduce the Thread dump structure, nor will it introduce the comprehensive use of tools in tuning process, such as ps,top,iostat,jstack,TDA plugin,Thread inspector. If you have any questions, welcome. Message exchange. Later, we will consider the thread/process model of xUnix and Windows platforms for in-depth analysis, and hope you like it.

ok, back to the truth. Above:

                                                    

Java has six thread states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING and TERMINATED. Here we focus on the BLOCKED and TIMED_WAITING states.

BLOCKED state: Typically, threads enter this state on two premises: wait for monitor (intrinsic or external) entry or reenter synchronization block. Let's start with two queues in the Java threading model. As shown in the figure:


                                     


At some point, each Monitor can only be owned by one thread, which is "Active Thread", while the other threads are "Waiting Thread", waiting in two queues "Entry Set" and "Wait Set". The thread state waiting for "Entry Set" is "Waiting for monitor entry", while the thread state waiting for "Wait Set" is "in Object.wait()". If you do not use the ReentrantLock or ReentrantReadWriteLock class properly, you may fall into the BLOCKED state, which is a common situation in our tuning. The solution is also simple. Find the address waiting for the lock and analyze whether Thread starvation has occurred.
As for the TIME_WAITING state, the official document also explains it better, that is, when you call the following method, the thread will enter the state.

 

          Thread.sleep 
	  Object.wait with timeout 
	  Thread.join with timeout 
	  LockSupport.parkNanos 
	  LockSupport.parkUntil

 

LockSupport is a basic thread blocking primitive for creating locks and other synchronization classes, an optimization for Thread.suspend and Thread.resume(), and an optimization for busy, etc. to prevent excessive spin. (For this, interested students can refer to document 5.) )


ok, after briefly introducing several key thread states, we look at Thread stack through several specific case s:

Case 1: Acceptor in NIO

"qtp589745448-36 Acceptor0 SelectChannelConnector@0.0.0.0:8161" prio=10 tid=0x00007f02f8eea800 nid=0x18ee runnable [0x00007f02e70b3000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241)
	- locked <0x00000000ec8ffde8> (a java.lang.Object)
	at org.eclipse.jetty.server.nio.SelectChannelConnector.accept(SelectChannelConnector.java:109)
	at org.eclipse.jetty.server.AbstractConnector$Acceptor.run(AbstractConnector.java:938)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
	at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
	- None

Look at how the source code is implemented, as follows:

 

public void accept(int acceptorID) throws IOException
100    {
101        ServerSocketChannel server;
102        synchronized(this)
103        {
104            server = _acceptChannel;
105        }
106
107        if (server!=null && server.isOpen() && _manager.isStarted())
108        {
109            SocketChannel channel = server.accept();
110            channel.configureBlocking(false);
111            Socket socket = channel.socket();
112            configure(socket);
113            _manager.register(channel);
114        }
115    }

 

With regard to Thread stack, here's an emphasis: nid, native lwp id, which is the local lightweight process (thread) ID.

Case 2: Selector from NIO

 

"qtp589745448-35 Selector0" prio=10 tid=0x00007f02f8ee9800 nid=0x18ed runnable [0x00007f02e71b4000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
	at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:228)
	at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:81)
	at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
	- locked <0x00000000ec9006f0> (a sun.nio.ch.Util$2)
	- locked <0x00000000ec9006e0> (a java.util.Collections$UnmodifiableSet)
	- locked <0x00000000ec9004c0> (a sun.nio.ch.EPollSelectorImpl)
	at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
	at org.eclipse.jetty.io.nio.SelectorManager$SelectSet.doSelect(SelectorManager.java:569)
	at org.eclipse.jetty.io.nio.SelectorManager$1.run(SelectorManager.java:290)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
	at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
	- None


The code snippet is as follows:

 

 

       // If we should wait with a select
566                     if (wait>0)
567                     {
568                         long before=now;
569                         selector.select(wait);
570                         now = System.currentTimeMillis();
571                         _timeout.setNow(now);
572 
573                         // If we are monitoring for busy selector
574                         // and this select did not wait more than 1ms
575                         if (__MONITOR_PERIOD>0 && now-before <=1)
576                         {
577                             // count this as a busy select and if there have been too many this monitor cycle
578                             if (++_busySelects>__MAX_SELECTS)
579                             {
580                                 // Start injecting pauses
581                                 _pausing=true;
582 
583                                 // if this is the first pause
584                                 if (!_paused)
585                                 {
586                                     // Log and dump some status
587                                     _paused=true;
588                                     LOG.warn("Selector {} is too busy, pausing!",this);
589                                 }
590                             }
591                         }
592                     }

 

Case 3: Handler for MQTT protocol in ActveMQ

 

"ActiveMQ Transport Server Thread Handler: mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600" daemon prio=10 tid=0x00007f02f8ba6000 nid=0x18dc waiting on condition [0x00007f02ec824000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000faad0458> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
	at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
	at org.apache.activemq.transport.tcp.TcpTransportServer$1.run(TcpTransportServer.java:373)
	at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
	- None

Code snippet:

 

 

  @Override
    protected void doStart() throws Exception {
        if (useQueueForAccept) {
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    try {
                        while (!isStopped() && !isStopping()) {
                            Socket sock = socketQueue.poll(1, TimeUnit.SECONDS);
                            if (sock != null) {
                                handleSocket(sock);
                            }
                        }

                    } catch (InterruptedException e) {
                        LOG.info("socketQueue interuppted - stopping");
                        if (!isStopping()) {
                            onAcceptError(e);
                        }
                    }
                }
            };
            socketHandlerThread = new Thread(null, run, "ActiveMQ Transport Server Thread Handler: " + toString(), getStackSize());
            socketHandlerThread.setDaemon(true);
            socketHandlerThread.setPriority(ThreadPriorities.BROKER_MANAGEMENT - 1);
            socketHandlerThread.start();
        }
        super.doStart();
    }

Case 5: Simulated Bank Transfer Deposit

"withdraw" prio=10 tid=0x00007f3428110800 nid=0x2b6b waiting for monitor entry [0x00007f34155bb000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.von.thread.research.DeadThread.depositMoney(DeadThread.java:13)
	- waiting to lock <0x00000000d7fae540> (a java.lang.Object)
	- locked <0x00000000d7fae530> (a java.lang.Object)
	at com.von.thread.research.DeadThread.run(DeadThread.java:28)
	at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
	- None

"deposit" prio=10 tid=0x00007f342810f000 nid=0x2b6a waiting for monitor entry [0x00007f34156bc000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.von.thread.research.DeadThread.withdrawMoney(DeadThread.java:21)
	- waiting to lock <0x00000000d7fae530> (a java.lang.Object)
	- locked <0x00000000d7fae540> (a java.lang.Object)
	at com.von.thread.research.DeadThread.run(DeadThread.java:29)
	at java.lang.Thread.run(Thread.java:724)

   Locked ownable synchronizers:
	- None
Found one Java-level deadlock:
=============================
"withdraw":
  waiting to lock monitor 0x00007f3400003620 (object 0x00000000d7fae540, a java.lang.Object),
  which is held by "deposit"
"deposit":
  waiting to lock monitor 0x00007f3400004b20 (object 0x00000000d7fae530, a java.lang.Object),
  which is held by "withdraw"

Java stack information for the threads listed above:
===================================================
"withdraw":
	at com.von.thread.research.DeadThread.depositMoney(DeadThread.java:13)
	- waiting to lock <0x00000000d7fae540> (a java.lang.Object)
	- locked <0x00000000d7fae530> (a java.lang.Object)
	at com.von.thread.research.DeadThread.run(DeadThread.java:28)
	at java.lang.Thread.run(Thread.java:724)
"deposit":
	at com.von.thread.research.DeadThread.withdrawMoney(DeadThread.java:21)
	- waiting to lock <0x00000000d7fae530> (a java.lang.Object)
	- locked <0x00000000d7fae540> (a java.lang.Object)
	at com.von.thread.research.DeadThread.run(DeadThread.java:29)
	at java.lang.Thread.run(Thread.java:724)

Found 1 deadlock.

 

Here is a deadlock scenario induced by a non-sequential locking.


All right, that's about it. To sum up, in the process of tuning, we focus on the following three types of situations:

1. wait for monitor entry-thread state blocked. Possible problems: deadlock (sequential deadlock, starvation deadlock...)
2. waiting on condition - sleeping or timed_waiting. Possible problems: IO bottleneck
Object.wait-TIMED_WAITING. Question: The performance and limitations of wait & notify All need to be clarified. External locks, more consideration is given to using await and singal methods.

Reference:

 

  1. http://architects.dzone.com/articles/how-analyze-java-thread-dumps

  2. http://stackoverflow.com/questions/7698861/simple-java-example-runs-with-14-threads-why

  3. http://www.longene.org/forum/viewtopic.php?f=5&t=94&p=399#p399

  4. http://www.slideshare.net/Byungwook/analysis-bottleneck-in-j2ee-application

  5. http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

  6. http://www.artima.com/insidejvm/ed2/threadsynch.html

  7. JavaConcurrency in practice

 

 

Reprinted at: https://www.cnblogs.com/riasky/p/3471472.html

Tags: Java Eclipse Jetty socket

Posted on Sat, 27 Jul 2019 03:25:38 -0700 by y_oda2002