When programming in a concurrent environment, it is necessary to use the lock mechanism to synchronize the operation between multiple threads to ensure mutually exclusive access to shared resources. Locking can cause performance damage, which seems to be a well-known thing. However, the lock itself does not bring much performance consumption, the performance is mainly the process of acquiring locks on the thread. If there is only one thread competing for the lock, there is no multi-threaded competition, then the JVM will be optimized, then the performance consumption of locking can be ignored. Therefore, the specification lock operation, optimizes the use method of the lock, avoids the unnecessary thread competition, may not only improve the program performance, but also can avoid the non-standard locking may cause the thread deadlock problem, enhances the program robustness. The following is a description of several lock optimization ideas.
First, try not to lock the method
When a lock is added to an ordinary member function, the thread obtains the object lock of the object on which the method resides. The entire object will be locked at this time. This also means that if the object provides multiple synchronization methods for different businesses, then because the entire object is locked, and a business business is processing, other unrelated business threads must wait. The following example shows the situation:
The LockMethod class contains two synchronous methods, which are called in two business processes, respectively:
Public classLockMethod { Public synchronized voidBusia () { for(inti = 0; I < 10000; i++) {System.out.println (Thread.CurrentThread (). GetName ()+ "deal with bussiness A:" +i); } } Public synchronized voidBusib () { for(inti = 0; I < 10000; i++) {System.out.println (Thread.CurrentThread (). GetName ()+ "deal with bussiness B:" +i); } }}
Bussa is a thread class that is used to handle a business, and calls the LockMethod Busia () method:
Public class extends Thread { lockmethod lockmethod; void deal (LockMethod lockmethod) { this. LockMethod= lockmethod; } @Override publicvoid run () { Super. Run (); Lockmethod.busia (); }}
BUSSB is a thread class that is used to handle the B business and calls the LockMethod Busib () method:
Public class extends Thread { lockmethod lockmethod; void deal (LockMethod lockmethod) { this. LockMethod= lockmethod; } @Override publicvoid run () { Super. Run (); Lockmethod.busib (); }}
The Testlockmethod class, which uses thread Bussa and BUSSB for business processing:
public class Testlockmethod extends public static void main (string[] args) {Lockme Thod LockMethod = LockMethod (); Bussa Bussa = Bussa (); BUSSB BUSSB = BUSSB (); Bussa.deal (LockMethod); Bussb.deal (LockMethod); Bussa.start (); Bussb.start (); }}
Running the program, you can see that the process of Bussa execution, BUSSB is not able to enter the function Busib (), because the LockMethod object lock is obtained by thread Bussa.
Second, narrow the synchronization code block, lock only the data
Sometimes for programming convenience, some people will synchnoized a very large piece of code, if some operations in this code block are not related to shared resources, then you should put them outside the synchronization block, to avoid long holding locks, causing other threads have been waiting state. In particular, some cyclic operations, synchronous I/O operations. Not only in the range of lines of code to narrow the synchronization block, in the execution of logic, you should also reduce the synchronization block, such as additional conditions to determine, meet the conditions of the synchronization, rather than synchronization after the conditional judgment, to minimize unnecessary logic to enter the synchronization block.
Third, try not to include the lock in the lock
This happens frequently, after the thread has got a lock, the synchronous method of the synchronization methods block calls the synchronization method of the other object, the second lock is obtained, which may lead to a multiple lock request in the call stack, the multi-threaded case can be complex, difficult to analyze the abnormal situation, resulting in the occurrence of deadlocks. The following code shows the situation:
synchronized (A) { synchronized(B) { } }
Or a synchronous method is called in the synchronization block:
synchronized (A) { B = objarraylist.get (0); // This is a synchronous method }
The solution is to jump out of the lock and not include the lock:
{ null; synchronized (A) { = objarraylist.get (0); } B.method ();}
Four, the lock is privatized, the internal management lock
The lock as a private object, the outside can not get this object, more secure. The object may be locked directly by another thread, and the thread holds the object lock for that object, such as the following:
class A { publicvoid method1 () { }}class B { Publicvoid method1 () { new A (); synchronized // Direct Lock-in
A.method1 ();
} }}
In this way, object A's object lock is held externally, so that it is more dangerous to use the lock in many places outside, and it also puzzles the logic flow reading of the code. A better way is to manage the lock itself within the class itself, while the external synchronization scheme is required to provide synchronous operations by means of an interface:
class A { privatenew Object (); Public void method1 () { synchronized (lock) { } }}}class B { publicvoid method1 () { new A (); A.method1 (); }}
V. Proper lock decomposition
Consider the following procedure:
Public classGameserver { Publicmap<string, list<player>> tables =NewHashmap<string, list<player>>(); Public voidJoin (Player player, table table) {if(Player.getaccountbalance () >Table.getlimit ()) { synchronized(tables) {List<Player> tableplayers =Tables.get (Table.getid ()); if(Tableplayers.size () < 9) {tableplayers.add (player); } } } } Public voidLeave (Player player, table table) {/*omitted*/} Public voidCreateTable () {/*omitted*/} Public voidDestroytable (table table) {/*omitted*/}}
In this example, the Join method uses only one synchronization lock to get the List<player> object in tables and then determines if the number of players is less than 9, and if so, adds a player. When there are thousands of list<player> present in tables, the competition for tables locks will be fierce. Here, we can consider the decomposition of locks: after quickly fetching data, list<player> objects are locked, allowing other threads to compete quickly for tables object locks:
Public classGameserver { Publicmap<string, list<player>> tables =NewHashmap<string, list<player>>(); Public voidJoin (Player player, table table) {if(Player.getaccountbalance () >Table.getlimit ()) {List<Player> tableplayers =NULL; synchronized(tables) {tableplayers=Tables.get (Table.getid ()); } synchronized(tableplayers) {if(Tableplayers.size () < 9) {tableplayers.add (player); } } } } Public voidLeave (Player player, table table) {/*omitted*/} Public voidCreateTable () {/*omitted*/} Public voidDestroytable (table table) {/*omitted*/}}
Finish
Java multithreaded Programming-lock optimization