Writing concurrent code is more difficult, although the Java language provides a lot of synchronization and concurrency support, but ultimately it takes a person's diligence and expertise to write Java concurrency code without bugs. Java multithreaded concurrency best practices are a good set of practical ideas that help you quickly develop high quality concurrent code. If you are a novice, you need to be familiar with some basic concepts, and then read this article will be more targeted.
1. Use local variables
You should always use a local variable instead of creating a class or instance variable, and typically, developers using object instances as variables can save memory and can be reused because they think it consumes a lot of memory each time you create a local variable in a method. The Execute () method of the following code is called by multithreading, in order to implement a new function, you need a temporary set collection, which is used as a static class variable in the code, and then clears the collection at the end of the Execute method for reuse. The person who wrote this code might think it's thread-safe, because copyonwritearraylist is thread-safe, but he doesn't realize that this method execute () is called by multiple threads, and that one thread in a multiple-thread can see the temporary data of another thread, Even using collections.synchronizedlist does not guarantee the logical invariance within the Execute () method: This is a temporary collection that can only be visible within each thread's execution and not exposed to other threads.
2. Using Immutable classes
Immutable classes such as String integer once created and no longer changed, immutable classes can reduce the number of synchronizations needed in your code.
3. Scope of minimizing locks
Any code in the lock will not be executed concurrently. If you have 5% code in the lock, then according to Amdahl's, your application image can not be increased by more than 20 times times, because the lock in the code only sequential execution, reduce the scope of the lock, locking and unlocking the code between the less the better.
4. Use thread pool Excutor instead of direct new thread to perform
The cost of creating a thread is expensive, and if you want to get a scalable Java application, you need to use a thread pool to manage threads. JDK provides a variety of threadpool thread pools and executor.
5. Rather than using a thread's wait notify to sync with a wet suit
Since Java 1.5 has increased the need for synchronization tools such as Cycicbariier, Countdownlatch, and Sempahore, you should prioritize these synchronization tools instead of thinking about how to use thread wait and notify, Achieving production-consumption through blockingqueue is much better than using threads of wait and notify, or you can use Countdownlatch to implement multiple thread waits:
Import Java.util.Date;
Import Java.util.concurrent.CountDownLatch;
Import Java.util.logging.Level;
Import Java.util.logging.Logger; /** * Java program to demonstrate how to use Countdownlatch in Java. Countdownlatch is * Useful if your want to start main processing thread once it dependency is completed * as Illustrat Ed in this countdownlatch Example * * @author javin Paul */public class Countdownlatchdemo {public static
void Main (String args[]) {final Countdownlatch latch = new Countdownlatch (3);
Thread cacheservice = new Thread (New Service ("Cacheservice", 1000, latch));
Thread alertservice = new Thread (New Service ("Alertservice", 1000, latch));
Thread validationservice = new Thread (New Service ("Validationservice", 1000, latch)); Cacheservice.start (); Separate thread would initialize Cacheservice Alertservice.start (); Another thread for Alertservice initialization Validationservice.start ();
Application should not start processing the any thread until the all service are up//and ready to do there job. Countdown latch is idle choice here, main thread would start with count 3//And wait until count reaches Zer O. Each thread once up and read'll do//a count down.
This would ensure that main thread isn't started processing//until all services are up. The count is 3 since we have 3 Threads (Services) try{latch.await (); Main thread is waiting on Countdownlatch to finish System.out.println ("All services are up, application is
Starting now ");
}catch (Interruptedexception IE) {ie.printstacktrace ();
}}/** * Service class which is executed by Thread using Countdownlatch synchronizer.
* * Class Service implements runnable{private final String name;
private final int timetostart; Private Final COuntdownlatch latch;
The public Service (String name, int timetostart, Countdownlatch latch) {this.name = name;
This.timetostart = Timetostart;
This.latch = latch;
@Override public void Run () {try {thread.sleep (Timetostart);
The catch (Interruptedexception ex) {Logger.getlogger (Service.class.getName ()). log (Level.severe, NULL, ex);
} System.out.println (name + "is"); Latch.countdown (); Reduce count of Countdownlatch by 1}}
Output:
Validationservice is up
Alertservice is up
Cacheservice is up
All services are up, application are starting now
6. Using Blockingqueue to achieve production-consumption patterns
Most concurrency problems can be implemented using Producer-consumer production-consumption design, while Blockingqueue is the best way to do it, blocking queues that can handle not only individual production individual consumption, but also multiple production and consumption. The following code:
Import Java.util.concurrent.BlockingQueue;
Import Java.util.concurrent.LinkedBlockingQueue;
Import Java.util.logging.Level;
Import Java.util.logging.Logger;
public class Producerconsumerpattern {public static void main (String args[]) {//creating Shared object
Blockingqueue sharedqueue = new Linkedblockingqueue ();
Creating Producer and Consumer thread thread prodthread = new Thread (new Producer (Sharedqueue));
Thread consthread = new Thread (new Consumer (Sharedqueue));
Starting producer and Consumer thread Prodthread.start ();
Consthread.start (); }//producer class in Java class Producer implements Runnable {private final blockingqueue Sharedqueue
;
Public Producer (Blockingqueue sharedqueue) {this.sharedqueue = Sharedqueue; @Override public void Run () {for (int i=0; i<10; i++) {try {Syst Em.out.println ("produced: "+ i);
Sharedqueue.put (i); The catch (Interruptedexception ex) {Logger.getlogger (Producer.class.getName ()). log (Level.severe, NULL, EX
); {}}}//consumer class in Java class Consumer implements runnable{private final Blocking
Queue Sharedqueue;
Public Consumer (Blockingqueue sharedqueue) {this.sharedqueue = Sharedqueue; @Override public void Run () {while (true) {try {System.out.println (
"Consumed:" + sharedqueue.take ()); The catch (Interruptedexception ex) {Logger.getlogger (Consumer.class.getName ()). log (Level.severe, NULL, EX
); }
}
}
}
Output:
produced:0
Produced:1
consumed:0
Produced:2
Consumed:1
Produced:3
Consumed:2
Produced:4
Consumed:3
Produced:5
Consumed:4
Produced:6
Consumed:5
Produced:7
Consumed:6
Produced:8
Consumed:7
Produced:9
Consumed:8
Consumed:9
7. Use concurrent collection collection instead of a synchronized lock
Java provides concurrenthashmap copyonwritearraylist and Copyonwritearrayset as well as Blockingqueue Deque and Blockingdeque Five concurrent sets, prefer to use these sets, and do not use the collections.synchronizedlist such as a set of synchronized locks, copyonwritearraylist suitable for the main reading rarely write occasions, Concurrenthashmap is more commonly used concurrent collections
8. Use semaphore to create a bounded
In order to establish a reliable and stable system, the database file system and sockets and other resources must be bounded bound,semaphore is a can limit the cost of these resources, if a resource can not, use semaphore can be the lowest cost blocking thread waiting:
Import Java.util.concurrent.Semaphore;
public class Semaphoretest {semaphore binary = new semaphore (1);
public static void Main (String args[]) {final semaphoretest test = new Semaphoretest ();
New Thread () {@Override public void run () {test.mutualexclusion ();
}}.start ();
New Thread () {@Override public void run () {test.mutualexclusion ();
}}.start ();
private void Mutualexclusion () {try {binary.acquire (); Mutual Exclusive Region System.out.println (Thread.CurrentThread () getName () + "inside Mutual exclusive-Regi
On ");
Thread.Sleep (1000);
catch (interruptedexception i.e.) {ie.printstacktrace ();
finally {binary.release (); System.out.println (Thread.CurrentThread (). GetName () + "Outside of MutuAl exclusive region ");
}
}
}
Output:
Thread-0 inside Mutual Exclusive region
Thread-0 outside of Mutual exclusive region
Thread-1 inside Mutual Exclusive region
Thread-1 outside of Mutual exclusive region
9. Prefer to use synchronized code block, and do not use the method of adding synchronization
Using synchronized to synchronize blocks of code locks only one object without locking the current whole method, and if you change the field of a common variable or class, first select the atomic variable and then use volatile. If you need a mutex, you can consider using Reentrantlock
10. Avoid using static variables
Static variables create a lot of problems in a concurrent execution environment, and if you have to use a static variable to call it a final constant, consider using a read-only collection if you want to save the collection collection.
11. Prefer to use locks rather than synchronized synchronization keywords
Lock lock interface is very powerful, fine-grained, for read and write operations have different locks, so that can easily expand scaling, and synchronized will not automatically release locks, if you use Lock () lock, you can use unlock unlock:
Lock.lock ();
try {
//do something ...
} finally {
lock.unlock ();
}
Turn from: http://www.jdon.com/concurrent/java-multithreading-best-pratices.html