I. definition of Popular science
The two main characters of this blog are "synchronized" and "read-write lock"
1) Synchronized
This sync keyword believes that we all use more, in the previous article "How to share data among multiple threads" also detailed list of his application, in this don't say only a few points:
- Java provides this keyword with built-in support for preventing resource conflicts. When a task executes to a code fragment that is synchronized protected, it checks to see if the lock is available, then acquires the lock, executes the code, and releases the lock.
- This keyword can be used to modify member methods and code blocks
2) read/write lock
There are two things we do with data: "read" and "write", imagine a scenario where 10 threads should not be synchronized when they read a data at the same time. The answer is not necessary. Only the following two conditions need to be synchronized:
- These 10 threads have both a read and a write on this public data
- These 10 threads write to the public data
- The above two points to the point is that there is a change in the data of the operation will need to synchronize
So
JAVA5 provides a read-write lock that supports multi-threaded read operations not mutually exclusive, multi-threaded read-write mutex, multi-threaded write mutex. Read operations are not mutually exclusive, which helps to improve performance, which was not before JAVA5
Two. Use a face test to compare these two points specifically
Title:"Whiteboard programming, Implementing a caching system"
Topic Analysis:
The understanding of this cache system: between the user and the database, we know that the user directly access the database time is far greater than direct access to memory, so after the user access to the buffer cache so that the user first access to the buffer cache when the user needs the data to be taken directly, when the buffer does not have such data, Access the database and put the access data in the buffer so that the next user who needs this data will have direct access to the memory.
Core Code implementation:First use synchronized to achieve
12345678 |
public synchronized Object getData(String key){
Object result = map.get(key);
if
(result ==
null
){
result =
"new"
;
//用这步代替访问数据库得数据
}
return result;
}
|
Implemented with read-write locks
1234567891011121314151617181920212223242526 |
public Object getData(String key){
rw.readLock().lock();
//在读前先上读锁
Object result =
null
;
try
{
result = map.get(key);
//这个if比较关键,它避免了多余的几次对数据哭的读取
if
(result==
null
){
//如果内存中没有所要数据
rw.readLock().unlock();
rw.writeLock().lock();
if
(result==
null
){
try
{
//我们用这个代替对数据库访问得到数据的步骤
result =
"new"
;
}
finally
{
rw.writeLock().unlock();
}
rw.readLock().lock();
}
}
}
finally
{
rw.readLock().unlock();
}
return result;
}
|
Code Analysis :
- The first method of processing, the whole process is relatively thick, the code is relatively simple single execution efficiency is very low. The central idea of this approach is that no matter what you do, everything involved in public resources will be synced to you. This can be done, but it's not good.
- The second type of reading and writing lock processing is obviously an optimization of the former, the second method is described as follows:
- As for the unlock operation, we know that as long as the lock is on, we have to unlock it, but there is a situation where there is a possibility that the program will be out of order before you perform the unlock operation. So for this problem we generally put the unlock operation in the finally code block, you can guarantee that the lock will definitely be solved.
- The above two times if judgment, the first if believe that everyone is well understood. But why use a second if? Assuming a scenario where 10 threads are now reading this data, and this data does not exist with the buffer, then the first thread in the 10 threads will execute "rw.writelock ()." Lock (); While the other nine threads will be blocked, the buffer actually has this data after the first thread has finished reading, but the other nine blocks in "Rw.writelock (). Lock (); If they do not add this layer if they will continue to access the database, thus adding this layer if the whole process has a great impact. This is a little bit more detail, just this Java API documentation is also considered, its sample code is as follows:
1234567891011121314151617181920212223242526 |
class CachedData {
Object data;
volatile boolean cacheValid;
ReentrantReadWriteLock rwl =
new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
<span style=
"color: #ff0000;"
>
if (!cacheValid)</span> {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
<span style=
"color: #ff0000;"
>
if (!cacheValid)</span> {
data = ...
cacheValid =
true
;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
rwl.writeLock().unlock();
// Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
|
Compare synchronized and read-write locks