In layman's Java Concurrency (39): Concurrent summary Part 3 common concurrency traps

Source: Internet
Author: User
Tags finally block

Common Concurrency trap volatile

Volatile can only emphasize the visibility of data and does not guarantee atomic operations and thread safety, so volatile is not a panacea. Re-ordering of reference instructions

Volatile is most commonly found in the following two scenarios.

A. Cyclic detection mechanism

Volatile Boolean done = false;


while (? done) {
DoSomething ();
}


B. Singleton model (http://www.blogjava.net/xylz/archive/2009/12/18/306622.html)

public class Doublelocksingleton {

Private static volatile Doublelocksingleton instance = null;

Private Doublelocksingleton () {
}

public static Doublelocksingleton getinstance () {
if (instance = = null) {
Synchronized (Doublelocksingleton.class) {
if (instance = = null) {
Instance = new Doublelocksingleton ();
}
}
}
return instance;
}
}


Synchronized/lock

It seems that lock has better performance and more flexible control, is it perfectly possible to replace the synchronized?

Some other issues with the lock say that synchronized's performance is getting higher with the JDK version, while the lock-optimized space is limited by CPU performance. In addition, the tool inside the JDK (thread dump) has some support for synchronized (easy to find deadlocks, etc.), and there is no support for lock.

There is no problem with simple logic using synchronized, which can be ignored as the performance of the machine increases. And it's simpler from a code structure. Simplicity is beauty.

For complex logic, you might consider using lock when it comes to read-write locks, condition variables, higher throughput, and more flexible, dynamic usage. Of course there is a particular need to pay attention to the correct use of lock.

Lock lock =
Lock.lock ();
try{
Do something
}finally{
Lock.unlock ();
}


Be sure to put the release of lock into the finally block, otherwise, if an exception or logical jump occurs, there is a risk that the lock will not be released and a deadlock can occur. And this deadlock is hard to troubleshoot.

Using Trylock () is a wise choice if it is necessary to synchronized an attempt to lock the mechanism, or to fear that a deadlock cannot be self-recoverable.

Lock lock =
if (Lock.trylock ()) {
try{
Do something
}finally{
Lock.unlock ();
}
}

You can even use a mechanism lock.trylock (Long,timeunit) that acquires a lock timeout over time. The use of the lock can refer to the previous article's description and recommendations.

Border of the lock

One of the popular mistakes is this.

concurrentmap<string,string> map = new concurrenthashmap<string,string> ();

if (!map.containskey (key)) {
Map.put (Key,value);
}


Seems reasonable, for a thread-safe map implementation, to access a non-repeating result, first detect whether it exists and then join. In fact, we know that two atomic operations and the sequence of instructions together are not meant to be thread-safe. The fragmentation of multiple atomic operations together in the case of multi-threaded can be an error.

In fact, Concurrentmap provides a "atomic manipulation" mechanism for putifabsent (K, V), which is equivalent to the following logic:

if (Map.containskey (key)) {
return Map.get (key);
}else{
Return Map.put (K,V);
}


In addition to the putifabsent there are two mechanisms for replace (K, V) and replace (K, V, v) to accomplish the combined operation.

Referring to map, here is a talk about HashMap read and write concurrency problems.

Constructor start thread

The following instance starts a thread in the constructor.

public class runner{
int x, y;
Thread thread;
Public Runner () {
This.x=1;
this.y=2;
This.thread=new MyThread ();
This.thread.start ();
}
}


A possible pitfall here is that if this class is inherited, the initiating thread may not be able to read the initialization operation of the subclass correctly.

Therefore, a simple principle is to prohibit the start of a thread in the constructor, consider but provide a way to start the thread. If you do this, it is best to set the class to final and disallow inheritance.

Issues with missing notifications

This article mentions the issue of notify lost notifications.

For Wait/notify/notifyall and Await/singal/singalall, if you're not sure exactly whether you can get the message correctly, worry about losing the notification, it's simple to always notify all.

If you are worried about receiving only one message, it is a good choice to use a loop to listen to it all the time.

A system with a very dominant performance may need to distinguish between notifying a single person or notifying all of the suspension.

Number of threads

Not the more threads, the better, the next article will be specific to understand the performance and scalability. Simply put, the number of threads does not have a fixed conclusion, is limited by the number of CPU cores, IO performance and dependent services, and so on. So choosing a suitable number of threads can help increase throughput.

For CPU-intensive applications, the number of threads and the number of cores in the CPU helps improve throughput, and all CPUs are busy and highly efficient. For IO-intensive applications, the number of threads is limited to the performance of Io, and at some point the single thread may be more efficient than multithreading. However, in general, the appropriate increase in the number of threads, is conducive to improve the efficiency of network IO, because we always think that network IO efficiency is low.

For the thread pool, selecting the appropriate number of threads and the task queue is a means of increasing the efficiency of the thread pool.

Public Threadpoolexecutor (
int Corepoolsize,
int Maximumpoolsize,
Long KeepAliveTime,
Timeunit Unit,
Blockingqueue<runnable> WorkQueue,
Threadfactory Threadfactory,
Rejectedexecutionhandler handler)


For the thread pool, if there is always a backlog of tasks, you can increase the corepoolsize size appropriately, and if the machine load is low, you can increase the maximumpoolsize size appropriately. , reducing the KeepAliveTime time in a task queue can help reduce the load, and the length of the task queue and the task queue's deny policy also have some impact on the processing of the task.

In layman's Java Concurrency (39): Concurrent summary Part 3 common concurrency traps

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.