The building owner, who is knocking code seriously, suddenly received an alarm email from the data maintenance system saying that the scheduled task of the building owner running early in the morning was not successful, so he started the process of looking for pit filling today.

For scheduled tasks, the choice between Timer and ScheduledExecutorService

I’m sure some friends will say why Quartz is not used, because the temple of the host is small, just a few scheduled tasks Quartz is too heavy.

Problems with Timer

The main problem with a Timer is that if the TimerTask throws an unchecked exception, the Timer will have unexpected behavior. The Timer thread does not catch exceptions, so an unchecked exception thrown by TimerTask terminates the Timer thread, in which case the Timer does not resume execution. It mistakenly assumes that the entire Timer has been cancelled. At this point, timerTasks that have been scheduled but not yet executed are never executed, and new tasks cannot be scheduled.

Using ScheduledExecutorService

ScheduledExecutorService is an API provided under the Concurrent package after JDK 1.5. The ScheduledExecutorService handles this exception properly, so using a Timer is not recommended in JDK1.5 or higher. If you are interested in executing a scheduled task in a thread pool, please use Java to terminate the task

Problems arising

ScheduledExecutorService is used instead of Timer. ScheduledExecutorService is used instead of Timer. ScheduledExecutorService is used for Timer. Of course, there is no need to mention the problems caused by using Timer. Let’s start our pit finding process

Check the log

Use the JStack tool provided by the JDK to obtain the jSTACK logs of the service, as shown in the following figure:


                                                

2018-07-18 15:39:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):

"Attach Listener" daemon prio=10 tid=0x00007f5bd0007800 nid=0x4e78 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" prio=10 tid=0x00007f5bec008800 nid=0x1dd5 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-4" prio=10 tid=0x00007f5bec4be000 nid=0x1df8 runnable [0x00007f5be88b2000]
   java.lang.Thread.State: RUNNABLE
	at java.net.PlainDatagramSocketImpl.receive0(Native Method)
	- locked <0x00000000e7e450b8> (a java.net.PlainDatagramSocketImpl)
	at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:146)
	- locked <0x00000000e7e450b8> (a java.net.PlainDatagramSocketImpl)
	at java.net.DatagramSocket.receive(DatagramSocket.java:816)
	- locked <0x00000000e7e450e8> (a java.net.DatagramPacket)
	- locked <0x00000000e7e45110> (a java.net.DatagramSocket)
	at com.yg84.chelaile.middleware.common.remotedata.protocol.udp.UDPReceiver$1.run(UDPReceiver.java:55)
	at java.lang.Thread.run(Thread.java:745)

"pool-5-thread-1" prio=10 tid=0x00007f5bec4ba800 nid=0x1df6 waiting on condition [0x00007f5be89b3000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000e7f1e510> (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.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

"kafka-producer-network-thread | producer-1" daemon prio=10 tid=0x00007f5bec497000 nid=0x1df2 runnable [0x00007f5be8ffe000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
	at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
	at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79)
	at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
	- locked <0x00000000e7e45778> (a sun.nio.ch.Util$2)
	- locked <0x00000000e7e45788> (a java.util.Collections$UnmodifiableSet)
	- locked <0x00000000e7e45730> (a sun.nio.ch.EPollSelectorImpl)
	at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
	at org.apache.kafka.common.network.Selector.select(Selector.java:454)
	at org.apache.kafka.common.network.Selector.poll(Selector.java:277)
	at org.apache.kafka.clients.NetworkClient.poll(NetworkClient.java:260)
	at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:229)
	at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:134)
	at java.lang.Thread.run(Thread.java:745)

"AsyncLoggerConfig-1" daemon prio=10 tid=0x00007f5bec32a800 nid=0x1dee waiting on condition [0x00007f5bf04c2000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000e7638090> (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 com.lmax.disruptor.BlockingWaitStrategy.waitFor(BlockingWaitStrategy.java:45)
	at com.lmax.disruptor.ProcessingSequenceBarrier.waitFor(ProcessingSequenceBarrier.java:55)
	at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:123)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

"Service Thread" daemon prio=10 tid=0x00007f5bec0b3800 nid=0x1ddc runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=10 tid=0x00007f5bec0b1000 nid=0x1ddb waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=10 tid=0x00007f5bec0ae800 nid=0x1dda waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x00007f5bec0ac800 nid=0x1dd9 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

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

"Reference Handler" daemon prio=10 tid=0x00007f5bec08a000 nid=0x1dd7 in Object.wait() [0x00007f5bf173b000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00000000e74a0848> (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 <0x00000000e74a0848> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x00007f5bec085800 nid=0x1dd6 runnable 

"VM Periodic Task Thread" prio=10 tid=0x00007f5bec0b7000 nid=0x1ddd waiting on condition 

JNI global references: 165

 Copy the code

Through the jstack logs and found no thread deadlocks, and also see the building open ScheduledThreadPoolExecutor also in normal operation, and found no problem.


                                                
"pool-5-thread-1" prio=10 tid=0x00007f5bec4ba800 nid=0x1df6 waiting on condition [0x00007f5be89b3000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000e7f1e510> (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.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)

 Copy the code

With the source code

ScheduledExecutorService does not execute scheduleAtFixedRate

/** * Creates and executes a periodic action that becomes enabled first * after the given initial delay, and subsequently with the given * period; that is executions will commence after * {@code initialDelay} then {@code initialDelay+period}, then * {@code initialDelay + 2 * period}, and so on. * If any execution of the task * encounters an exception, subsequent executions are suppressed. * Otherwise, the task will only terminate via cancellation or * termination of the executor. If any execution of this task * takes longer than its period, then subsequent executions * may start late, but will not concurrently execute. * * @param command the task to execute * @param initialDelay the time to delay first execution * @param period the period between successive executions * @param unit the time unit of the initialDelay and period parameters * @return a ScheduledFuture representing pending completion of * the task, and whose {@code get()} method will throw an * exception upon cancellation * @throws RejectedExecutionException if the task cannot be * scheduled for execution * @throws NullPointerException if command is null * @throws IllegalArgumentException if period less than or equal to zero */ public ScheduledFuture<? > scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);Copy the code

Sure enough, the following statement in the method doc tells you that the task will stop executing when it encounters an exception. Of course, other tasks are unaffected.

If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor. If any execution of this task takes longer  than its period, then subsequent executions may start late, but will not concurrently execute.Copy the code

analyse

ScheduledExecutorService (ScheduledExecutorService (ScheduledExecutorService, ScheduledExecutorService (ScheduledExecutorService, ScheduledExecutorService, ScheduledExecutorService (ScheduledExecutorService, ScheduledExecutorService)))

public class TestCase { public static void main (String[] args) { ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); service.scheduleAtFixedRate(new TestJob(), 0, 1000, TimeUnit.MILLISECONDS); service.scheduleAtFixedRate(new TestJob2(), 0, 1000, TimeUnit.MILLISECONDS); } static class TestJob implements Runnable { int count = 0; public TestJob() { } @Override public void run() { // try { count++; System.out.println("TestJob count : " + count); if (count == 5) { throw new NullPointerException(); } // } catch (Exception e) { // e.printStackTrace(); // } } } static class TestJob2 implements Runnable { int count = 0; public TestJob2() { } @Override public void run() { count++; System.out.println("TestJob2 count : " + count); }}}Copy the code

TestJob throws an exception, and TestJob2 continues to execute.

The results

Problem solving

Once the root cause of the problem is found, it is relatively easy to solve it. The specific code is shown below

static class TestJob implements Runnable { int count = 0; public TestJob() { } @Override public void run() { try { count++; System.out.println("TestJob count : " + count); if (count == 5) { throw new NullPointerException(); } } catch (Exception e) { e.printStackTrace(); }}}Copy the code

summary

In general, this problem is relatively simple, relatively hidden. Of course, it has a lot to do with your usual coding specification.

Author: the original haifeiWu link: www.hchstudio.cn/article/201… Copyright notice: all non-special notices are original works of this website, please indicate the author and original link when reprinting.