This article can be used as a learning note for the Zhang Xiaoxiang-java multi-threading and concurrency Library advanced application.
In this section we do a caching system.
Before reading the festival
Please read first
Reentrantreadwritelock use of read/write locks 1
First edition
public class Cachedemo { private map<string, object> cache = new hashmap<string, object> (); public static void Main (string[] args) { Cachedemo cd = new Cachedemo (); SYSTEM.OUT.PRINTLN ("SS " +cd.getdata2 ("ss")); SYSTEM.OUT.PRINTLN ("SS " +cd.getdata2 ("ss")); System.out.println ("MM" +cd.getdata2 ("MM" )); System.out.println ("MM" +cd.getdata2 ("mm")); } Public Object getData2 (String key) { object O=cache.get (key); if (o==null) { //logo 1 System.out.println ("first check not" +key); O=math.random (); Actually get cache.put (Key, O) from the database; } return o; }}
Operation Result:
First Check no SS
SS 0.4045014284225158
SS 0.4045014284225158
First Check no mm
MM 0.9994663041529088
MM 0.9994663041529088
There seems to be no problem.
What do you think?
If there are three threads at the same time for the first time to the identity of GetData2 () 1 (the key you are looking for is the same), check o is null, and then go to the database. In this case, it is equal to three lines Cheng Cha the same key, and then all went to the database.
This is obviously unreasonable.
The simplest way to synchronized the second edition
Public synchronized Object getData2 (String key) {
//.....
}
The third edition of the lock section we mentioned that Reentrantlock can replace synchronized, which is a more object-oriented design. Let's try it.
Private Lock l=new Reentrantlock (); L as member variable of Cachedemo public Object getData3 (String key) { l.lock (); Object O=null; try { o = cache.get (key); if (o = = null) {//ID 1 System.out.println ("first check no" + key); o = Math.random (); Actually get cache.put (Key, O) from the database, } } finally { l.unlock (); } return o; }
Can I have the third edition?
Can be a p.
Why, think for yourself.
We have to use Reentrantreadwritelock, which has both a read lock and a write lock in the same method.
First, I have another question:
For the same thread, can you add a read lock and then write the lock before unlocking the read lock?
In other words, does the following code stop?
public class Cachedemo { private map<string, object> cache = new hashmap<string, object> (); Private Readwritelock RWL = new Reentrantreadwritelock (); public static void Main (string[] args) { Cachedemo cd = new Cachedemo (); Cd.getdata2 (); } public void GetData2 () { rwl.readlock (). Lock (); SYSTEM.OUT.PRINTLN (1); Rwl.writelock (). Lock (); SYSTEM.OUT.PRINTLN (2); Rwl.readlock (). Unlock (); SYSTEM.OUT.PRINTLN (3); Rwl.writelock (). Unlock (); SYSTEM.OUT.PRINTLN (4);} }
Try it yourself, the console output 1, the program will not move.
the read lock must be unlocked before the write lock is added.
The fourth edition is a read lock and a write lock
public static void Main (string[] args) {Cachedemo cd = new Cachedemo (); SYSTEM.OUT.PRINTLN ("ss" +cd.getdata4 ("ss")); SYSTEM.OUT.PRINTLN ("ss" +cd.getdata4 ("ss")); System.out.println ("MM" +cd.getdata4 ("mm")); System.out.println ("MM" +cd.getdata4 ("mm")); Public Object getData4 (String key) {Rwl.readlock (). Lock (); Object O=null; try {o=cache.get (key); if (o==null) {System.out.println ("first check not" +key); Rwl.readlock (). Unlock (); Identification 4 Rwl.writelock (). Lock (); try {if (value==null) {//id 0 value = "AAAA";//Actual call to Querydb (); Cache.put (Key,value); }} finally {Rwl.writelock (). Unlock (); } rwl.readlock (). Lock (); ID 1}}finally {Rwl.readlock (). Unlock (); Callout 2 } return o; }
Results
First Check no SS
SS 0.5989899889645358
SS 0.5989899889645358
First Check no mm
MM 0.8534424949014686
MM 0.8534424949014686
There are three more questions about this one.
1 Why you have to unlock at Mark 2.
This answer has been mentioned in the previous section.
2 Why is there a lock on the ID 1?
If the identity 1 is not locked, and the program has been performing normally, then to the identity 2, it unlocked whose lock?
3 Why do I have to check the ID 0 out?
If at the same time three threads run to identity 4 (looking for the same key), one obtains a write lock, writes the data, and releases the write lock. At this time another two threads still need to go to the database to run a trip?
In addition, the identification 1 of the reading lock, put in the front of finally called the downgrade lock. I'm not quite sure about the downgrade lock at the moment.
An example of a downgrade lock is given in the official documentation, as follows
Class Cacheddata { Object data; Volatile Boolean cachevalid; Final Reentrantreadwritelock rwl = new Reentrantreadwritelock (); void Processcacheddata () { rwl.readlock (). Lock (); if (!cachevalid) { //must release read lock before acquiring write lock rwl.readlock (). Unlock (); Rwl.writelock (). Lock (); try { //recheck state because another thread might has //acquired write lock and changed state before we did. if (!cachevalid) { data = ... Cachevalid = true; } Downgrade by acquiring read lock before releasing write lock Rwl.readlock (). Lock (); } finally { Rwl.wri Telock (). Unlock (); Unlock write, still hold read } } try {use data; } finally { rwl.readlock (). Unlock ( ); } } }
Thanks GLT
Reentrantreadwritelock use of read/write Locks 2