Suggestions for Java concurrent programming
using immutable objects whenever possible
In a concurrent application environment, immutable objects have the following advantages:
(1) Immutable objects, once created, cannot be modified by any threaded process, so there is no need to use a synchronization mechanism to protect their properties.
(2) There is no data consistency problem with immutable objects.
The only drawback is that you cannot modify an existing object, but instead create a new object.
In fact, the JDK also provides some immutable objects, such as String, BigDecimal, BigInteger and LocalDateTime, and so on.
To implement an immutable class, you need to observe the following rules:
(1) The class is final.
(2) The attributes in the class are private final.
(3) The properties in the class must be initialized by the constructor. And the set method cannot be supplied.
(4) A Get method of a mutable property in a class that must provide protective copy by creating a new object return.
avoiding deadlocks by ordering locks
We look at a deadlock caused by improper lock order:
Package com.doctor.thread;
Import Java.util.concurrent.TimeUnit;
Import Java.util.concurrent.locks.Lock;
Import Java.util.concurrent.locks.ReentrantLock; /** * @author sdcuike * @date 2018/2/4 * @since 2018/2/4/public class Deadlock {private Lock Locka = new Reent
Rantlock ();
Private Lock lockb = new Reentrantlock ();
public void Operation1 () {locka.lock ();
Lockb.lock ();
try {TimeUnit.SECONDS.sleep (2);
System.out.println (Thread.CurrentThread ());
catch (Interruptedexception e) {e.printstacktrace ();
finally {Lockb.unlock ();
Locka.unlock ();
} public void Operation2 () {lockb.lock ();
Locka.lock ();
try {TimeUnit.SECONDS.sleep (2);
System.out.println (Thread.CurrentThread ());
catch (Interruptedexception e) {e.printstacktrace (); finally {Locka.unloCK ();
Lockb.unlock (); } public static void Main (string[] args) throws Interruptedexception {deadlock deadlock = new Dead
Lock ();
New Thread (()->{deadlock.operation1 ();
). Start ();
New Thread (()->{deadlock.operation2 ();
). Start ();
TimeUnit.SECONDS.sleep (5);
}
}
Run the program, sometimes you will see the process has not exited, the console without any input, we look at the process of the JVM at this time:
beaver:~ beaver$ JPS
8208 Launcher 8209 deadlock 8307 JPS 94498 77482 3342 Launcher
3343 Springapplicationboot
Process ID is 8209, let's take a look at the thread information:
beaver:~ beaver$ jstack 8209 2018-02-04 14:10:20 full thread dump Java HotSpot (TM) 64-bit Server VM (9.0.1+11 mixed mode): "Attach Listener" #16 daemon prio=9 os_prio=31 tid=0x00007fb2c7834000 nid=0x6307 waiting on condition [0x000000000000000 0] Java.lang.Thread.State:RUNNABLE "DESTROYJAVAVM" #15 prio=5 os_prio=31 tid=0x00007fb2c6008800 nid=0x1c03 waiting on condition [0x0000000000000000] Java.lang.Thread.State:RUNNABLE "Thread-1" #14 prio=5 os_prio=31 tid=0x00007fb2c58558 NID=0X7C03 waiting on condition [0x0000700010e7d000] Java.lang.Thread.State:WAITING (parking) at Jdk.internal.misc . Unsafe.park (Java.base@9.0.1/native method)-Parking to wait for <0x00000006cfdf5470> (a Java.util.concurrent.loc Ks.
Reentrantlock$nonfairsync) at Java.util.concurrent.locks.LockSupport.park (java.base@9.0.1/locksupport.java:194) At Java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt (JAVA.BASE@9.0.1/ abstractqueuedsynchronizer.java:871) at Java.util.concuRrent.locks.AbstractQueuedSynchronizer.acquireQueued (java.base@9.0.1/abstractqueuedsynchronizer.java:903) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire (Java.base@9.0.1/abstractqueuedsynchronizer.java : 1226) at Java.util.concurrent.locks.ReentrantLock.lock (java.base@9.0.1/reentrantlock.java:267) at Com.doctor.thread.DeadLock.operation2 (deadlock.java:32) at com.doctor.thread.deadlock.lambda$main$1 ( deadlock.java:52 com.doctor.thread.deadlock$ $Lambda $2/2114694065.run (Unknown Source) at Java.lang.Thread.run ( java.base@9.0.1/thread.java:844) "Thread-0" #13 prio=5 os_prio=31 tid=0x00007fb2c584f800 nid=0x7a03 on condition [0x0000700010d7a000] Java.lang.Thread.State:WAITING (parking) at Jdk.internal.misc.Unsafe.park (java.base@ 9.0.1/native method)-Parking to wait for <0x00000006cfdf54a0> (a JAVA.UTIL.CONCURRENT.LOCKS.REENTRANTLOCK$NONFA Irsync) at Java.util.concurrent.locks.LockSupport.park (java.base@9.0.1/locksupport.java:194) at Java.util.conCurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt (Java.base@9.0.1/abstractqueuedsynchronizer.java : 871) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued (JAVA.BASE@9.0.1/ abstractqueuedsynchronizer.java:903) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire (java.base@ 9.0.1/abstractqueuedsynchronizer.java:1226) at Java.util.concurrent.locks.ReentrantLock.lock (JAVA.BASE@9.0.1/ reentrantlock.java:267) at Com.doctor.thread.DeadLock.operation1 (deadlock.java:18) at Com.doctor.thread.deadlock.lambda$main$0 (deadlock.java:48) at com.doctor.thread.deadlock$ $Lambda $1/1170794006. Run (Unknown Source) at Java.lang.Thread.run (java.base@9.0.1/thread.java:844) "Service Thread" #12 daemon prio=9 Os_prio =31 tid=0x00007fb2c8006800 nid=0x7603 runnable [0x0000000000000000] Java.lang.Thread.State:RUNNABLE "Monitor ctrl-bre AK "#11 daemon prio=5 os_prio=31 tid=0x00007fb2c7824000 nid=0x7403 runnable [0x0000700010a71000] Java.lang.Thread.State : RunnablE at Java.net.SocketInputStream.socketRead0 (Java.base@9.0.1/native method) at Java.net.SocketInputStream.socketRead (java.base@9.0.1/socketinputstream.java:116) at Java.net.SocketInputStream.read (JAVA.BASE@9.0.1/ socketinputstream.java:171) at Java.net.SocketInputStream.read (java.base@9.0.1/socketinputstream.java:141) at Sun.nio.cs.StreamDecoder.readBytes (java.base@9.0.1/streamdecoder.java:284) at Sun.nio.cs.StreamDecoder.implRead (
java.base@9.0.1/streamdecoder.java:326) at Sun.nio.cs.StreamDecoder.read (java.base@9.0.1/streamdecoder.java:178) -Locked <0x00000006cfc55b58> (a java.io.InputStreamReader) at Java.io.InputStreamReader.read (JAVA.BASE@9.0.1/ inputstreamreader.java:185) at Java.io.BufferedReader.fill (java.base@9.0.1/bufferedreader.java:161) at Java.io.BufferedReader.readLine (java.base@9.0.1/bufferedreader.java:326)-Locked <0x00000006cfc55b58> (a Java.io.InputStreamReader) at Java.io.BufferedReader.readLine (java.base@9.0.1/bufferedreader.java:392) at COM. Intellij.rt.execution.application.appmainv2$1.run (appmainv2.java:64) "Common-cleaner" #10 daemon prio=8 os_prio=31 tid=0x00007fb2c9819800 nid=0x7203 in Object.wait () [0x000070001096e000] Java.lang.Thread.State:TIMED_WAITING (on Obje CT monitor) at Java.lang.Object.wait (Java.base@9.0.1/native method)-Waiting on <0x00000006cff37bc0> (a Java.lang . Ref. Referencequeue$lock) at Java.lang.ref.ReferenceQueue.remove (java.base@9.0.1/referencequeue.java:151)-Waiting to Re-lock in, () <0x00000006cff37bc0> (a java.lang.ref.referencequeue$lock) at Jdk.internal.ref.CleanerImpl.run (java.base@9.0.1/cleanerimpl.java:148) at Java.lang.Thread.run (JAVA.BASE@9.0.1/ thread.java:844) at Jdk.internal.misc.InnocuousThread.run (java.base@9.0.1/innocuousthread.java:122) "Sweeper Thread "#9 daemon prio=9 os_prio=31 tid=0x00007fb2c609b000 nid=0x7003 runnable [0x0000000000000000] Java.lang.Thread.St Ate:runnable "C1 CompilerThread3" #8 daemon prio=9 os_prio=31 tid=0x00007fb2c609a000NID=0X6E03 waiting on condition [0x0000000000000000] java.lang.Thread.State:RUNNABLE No compile task "C2 Hread2 "#7 daemon prio=9 os_prio=31 tid=0x00007fb2c7804800 nid=0x6c03 waiting on condition [0x0000000000000000] java.la Ng. Thread.State:RUNNABLE No Compile task "C2 CompilerThread1" #6 daemon prio=9 os_prio=31 tid=0x00007fb2c5818000 nid=0x6 A03 waiting on condition [0x0000000000000000] java.lang.Thread.State:RUNNABLE No compile task "C2 CompilerThread0" #5 Daemon prio=9 os_prio=31 tid=0x00007fb2c5817000 nid=0x6803 waiting on condition [0x0000000000000000] Java.lang.Thre Ad. state:runnable No Compile task "Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fb2c88ac800 nid=0x6603 Able [0x0000000000000000] Java.lang.Thread.State:RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fb2c606c nid=0x5603 in Object.wait () [0x00007000101d6000] Java.lang.Thread.State:WAITING, on Object Monitor, at Java.lang. Object.wait (java.bAse@9.0.1/native method)-Waiting on <0x00000006cff0d070> (a java.lang.ref.referencequeue$lock) at Java.lang.ref . Referencequeue.remove (java.base@9.0.1/referencequeue.java:151)-Waiting to Re-lock in wait () <0x00000006cff0d070 > (a Java.lang.ref.referencequeue$lock) at Java.lang.ref.ReferenceQueue.remove (JAVA.BASE@9.0.1/ referencequeue.java:172) at Java.lang.ref.finalizer$finalizerthread.run (java.base@9.0.1/finalizer.java:216) " Reference Handler "#2 daemon prio=10 os_prio=31 tid=0x00007fb2c606c000 nid=0x5403 waiting on condition [0x00007000100d300 0] Java.lang.Thread.State:RUNNABLE at Java.lang.ref.Reference.waitForReferencePendingList (java.base@9.0.1/native method) at Java.lang.ref.Reference.processPendingReferences (java.base@9.0.1/reference.java:174) at java.lang.ref.reference.access$000 (java.base@9.0.1/reference.java:44) at java.lang.ref.reference$ Referencehandler.run (java.base@9.0.1/reference.java:138) "VM Thread" os_prio=31 tid=0x00007fb2c9802800 nid=0x5203 runnable "GC thread#0" os_prio=31 tid=0x00007fb2c8805800 nid=0x2803 runnable "GC thread#1" os_prio=31 c8001000 nid=0x2a03 runnable "GC thread#2" os_prio=31 tid=0x00007fb2c8806000 (nid=0x2c03 runnable "GC thread#3" Os_prio =31 tid=0x00007fb2c8807000 nid=0x2e03 runnable "GC thread#4" os_prio=31 tid=0x00007fb2c9003000 nid=0x3003 runnable "GC Thread#5 "os_prio=31 tid=0x00007fb2c8807800 nid=0x3203 runnable" GC thread#6 "os_prio=31 tid=0x00007fb2c7801000 nid=0x3 403 runnable "GC thread#7" os_prio=31 tid=0x00007fb2c7802000 nid=0x3603 runnable "G1 Main Marker" os_prio=31 07fb2c8830800 nid=0x4a03 runnable "G1 marker#0" os_prio=31 tid=0x00007fb2c8831000 nid=0x4e03 runnable "G1 marker#1" os
_prio=31 tid=0x00007fb2c8831800 nid=0x5003 runnable "G1 refine#0" os_prio=31 tid=0x00007fb2c580b800 nid=0x4603 "G1 refine#1" os_prio=31 tid=0x00007fb2c880a800 nid=0x4403 runnable "G1 refine#2" os_prio=31 tid=0x00007fb2c8809800 N id=0x4203 runnable "G1Refine#3 "os_prio=31 tid=0x00007fb2c8809000 nid=0x4003 runnable" G1 refine#4 "os_prio=31 tid=0x00007fb2c7000800 E03 runnable "G1 refine#5" os_prio=31 tid=0x00007fb2c580b000 nid=0x3c03 runnable "G1 refine#6" os_prio=31 tid=0x00007f b2c9004800 nid=0x3a03 runnable "G1 refine#7" os_prio=31 tid=0x00007fb2c8808000 nid=0x3803 runnable "G1 Young Remset Sa Mpling "os_prio=31 tid=0x00007fb2c580c800 nid=0x4803 runnable" VM periodic Task Thread os_prio=31 tid=0x00007fb2c700700 0 nid=0x7803 waiting on condition JNI global references:133 Found one java-level deadlock: ========================== = = = "Thread-1": Waiting for Ownable Synchronizer 0x00000006cfdf5470, (a java.util.concurrent.locks.reentrantlock$ Nonfairsync), which is held by "Thread-0" "Thread-0": Waiting for Ownable Synchronizer 0x00000006cfdf54a0, (a Java.uti L.concurrent.locks.reentrantlock$nonfairsync), which is held by ' Thread-1 ' Java stack information for threads D Above: =================================================== "Thread-1": At Jdk.internal.misc.Unsafe.park (Java.base@9.0.1/native method)-Parking to Wait for <0x00000006cfdf5470> (a java.util.concurrent.locks.reentrantlock$nonfairsync) at Java.util.concurrent.locks.LockSupport.park (java.base@9.0.1/locksupport.java:194) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt (JAVA.BASE@9.0.1/ abstractqueuedsynchronizer.java:871) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued ( java.base@9.0.1/abstractqueuedsynchronizer.java:903) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire (Java.base@9.0.1/abstractqueuedsynchronizer.java : 1226) at Java.util.concurrent.locks.ReentrantLock.lock (java.base@9.0.1/reentrantlock.java:267) at Com.doctor.thread.DeadLock.operation2 (deadlock.java:32) at com.doctor.thread.deadlock.lambda$main$1 ( deadlock.java:52 com.doctor.thread.deadlock$ $Lambda $2/2114694065.run (Unknown Source) at Java.lang.Thread.run ( Java.base@9.0.1/thread.java:844) "Thread-0": At Jdk.internal.misc.Unsafe.park (Java.base@9.0.1/native method)-Parking to <0x00000006cfdf54a0> (a java.util.concurrent.locks.reentrantlock$nonfairsync) at Java.util.concurrent.locks.LockSupport.park (java.base@9.0.1/locksupport.java:194) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt (JAVA.BASE@9.0.1/ abstractqueuedsynchronizer.java:871) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued ( java.base@9.0.1/abstractqueuedsynchronizer.java:903) at Java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire (Java.base@9.0.1/abstractqueuedsynchronizer.java : 1226) at Java.util.concurrent.locks.ReentrantLock.lock (java.base@9.0.1/reentrantlock.java:267) at Com.doctor.thread.DeadLock.operation1 (deadlock.java:18) at com.doctor.thread.deadlock.lambda$main$0 ( deadlock.java:48 com.doctor.thread.deadlock$ $Lambda $1/1170794006.run (Unknown Source) at Java.lang.Thread.run ( Java.base@9.0.1/thread.java:844) Found 1 deadlock.
Found 1 deadlock, we found that the deadlock occurred. The above code is due to the improper locking sequence caused the deadlock occurred.
Detailed code: Https://github.com/sdcuike/java8-learning/blob/master/src/main/java/com/doctor/thread/DeadLock.java
So we are not accessing shared resources, the order of locks or the improper ordering of resources, it is easy to cause deadlock.
Sometimes we can't adjust the order of the locks, we can use Java.util.concurrent.locks.lock#trylock ():
Java.util.concurrent.locks.Lock
Boolean Trylock () acquires the Lock only if it's free at the time of
invocation.< C2/>acquires the lock if it is available and returns immediately with the value true. If the lock isn't available then this method would return immediately with the value false.
A typical usage idiom for this to would be:
lock lock = ...;
if (Lock.trylock ()) {
try {
//manipulate protected state
} finally {
lock.unlock ();
}
} else {
//Perform alternative actions
} This
usage ensures that the lock are unlocked if it was acquired, and Doe SN ' t try to unlock if the lock is not acquired.
Returns:
True if the lock was acquired and false otherwise
use atomic variables for appropriate scenarios
When multithreading shares resources, we generally protect the use of synchronization mechanisms for critical areas. What we use in Java is the Synchronization keyword synchronized and the Concurrency tool class lock.
Since Java5, it also provides a method: Atomic variable. The performance of an atomic variable is higher than the old synchronization mechanism because of the optimistic lock used by the atomic variable. Please refer to JDK package java.util.concurrent.atomic for details.
the smaller the size of the lock, the better .
The range of the critical area is about small, and we can use different locks to enable concurrent performance by splitting a large critical section into a few irrelevant critical sections.
Provide.
The representative is the concurrency container concurrenthashmap in the JDK, which provides concurrent performance through segmented locks.
prioritize using JDK executors to manage threads
prioritize the concurrency data structures provided by JDK instead of making wheels
concurrent data structures provided by JDK that's the masterpiece of concurrent Master Doug Lea, which is generally divided into two types: (1) non-blocking data structure (non-blocking data Structures) (2) Blocking data structure (blocking D ATA structures) Please refer to Java Package java.util.concurrent or other books in detail.
use Java 8 streams to handle large datasets
do not use obsolete thread APIs
Avoid blocking operations in locks
Reference:
Effective Java (3rd Edition)
Java 9 concurrency Cookbook-second Edition