ReentrantLock
ReentrantLock它实现了标准的互斥锁,即当一个线程获取了锁,其他的线程都要等待,当前线程释放锁才能获得所有权。一次最多只有一个线程持有锁。通常作为保护数据一致性很强的的加锁约束,这样也就限制了程序的并发效率。
虽然避免了 写---写,读---写 的线程安全问题,但是也同样避开了读读的的重叠。在很多的时候数据是被频繁读取的。
ReentrantReadWriteLock
它的出现就是为了解决多个线程读读互斥的问题。
我们先来看JavaDoc文档中两个获取锁模式 ------------:
- 不公平的(竞争)模式
* <dl>
* <dt><b><i>Non-fair mode (default)</i></b>
* <dd>When constructed as non-fair (the default), the order of entry
* to the read and write lock is unspecified, subject to reentrancy
* constraints. A nonfair lock that is continuously contended may
* indefinitely postpone one or more reader or writer threads, but
* will normally have higher throughput than a fair lock.
当创建一个非公平的锁,受制于重入的约束 ,它获得锁的读写顺序是没有被指定的。一个非公平的锁将会无限期的延误另一个读或者写的线程,但却拥有更高的吞吐量。
2.公平的模式
* <dt><b><i>Fair mode</i></b>
* <dd>When constructed as fair, threads contend for entry using an
* approximately arrival-order policy. When the currently held lock
* is released, either the longest-waiting single writer thread will
* be assigned the write lock, or if there is a group of reader threads
* waiting longer than all waiting writer threads, that group will be
* assigned the read lock.
- 线程不用一个近似到达的顺序来争夺进入,当线程释放锁时,会优先的选择一个单个的等待时间最长的读线程的来获得锁
- 如果有一组读线程的等待时间是大于所有的写线程是,这些读操作的线程会优先的获取
- 如果写锁被持有,或者有个写的线程在等待,去获取它的读锁就会发生阻塞。线程将不会获得读锁,直到在当前等待时间最长的写入线程获得并释放写入锁之后。
- 一个线程想要获得公平的写锁将会被阻塞,除非它的读锁或者写锁都是没有被占用的。即只要一个一线程获取公平写锁,只要它被读锁占用或者被写锁占用都会发生阻塞。
读写锁的作用: 刷新缓存,改进集合
package ReadWirteLock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*
* @author Administrator
*
*/
public class ReenterantLock {
private final ReentrantReadWriteLock readWriteLock =new ReentrantReadWriteLock();
private final Map<String,Object> cache = new HashMap<>();
private final Lock readlock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
//读的时候是可以被多个线程读取访问的
public Object get(String key) {
readlock.lock();
Object val;
try {
return cache.get(key);
} finally {
readlock.unlock();
}
}
public void set(String key,Object value) {
// Must release read lock before acquiring write lock or willed be blocked;
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}
测试锁降级:
package ReadWirteLock;
import java.sql.Time;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
*
* @author Administrator
*
*/
public class ReenterantLock {
private final ReentrantReadWriteLock readWriteLock =new ReentrantReadWriteLock();
private final Map<String,Object> cache = new HashMap<>();
private final Lock readlock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
//读的时候是可以被多个线程读取访问的
public Object get(String key) {
readlock.lock();
Object val;
try {
System.out.println("开始读取key:"+key);
return cache.get(key);
} finally {
System.out.println("结束key:"+key);
readlock.unlock();
}
}
public void set(String key,Object value) {
// Must release read lock before acquiring write lock or willed be blocked;
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
ReenterantLock reenterantLock =new ReenterantLock();
for(int i=0;i<10;i++) {
System.out.println("放置数据");
reenterantLock.set(String.valueOf(i), i);
}
Thread t1 =new Thread(() -> {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
reenterantLock.set("4", 4);
for(int i=0;i<3;i++) {
System.out.println("t1 开始锁降级 get key:"+i);
reenterantLock.get(String.valueOf(i));
}
});
Thread t2 =new Thread(() -> {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<10;i++) {
reenterantLock.get(String.valueOf(i));
}
});
t1.start();
t2.start();
}
}