- 声明读写锁:
private ReadWriteLock lock = new ReentrantReadWriteLock();
- 独占锁:
lock.writeLock()
- 共享锁:
lock.readLock()
一:无锁案例
在自定义类NoLockTest中存在一个数据变量map,类中存在一个读方法get和写方法put,则在多线程情况下,数据操作会出现错误。
public class RW {
public static void main(String[] args) {
NoLockTest my = new NoLockTest();
//存
for (int i = 1; i <=10 ; i++) {
final Integer number = i;
new Thread(()->{
my.put(number+"",number+"");
},"Thread"+String.valueOf(i)).start();
}
//取
for (int i = 1; i <=10 ; i++) {
final Integer number = i;
new Thread(()->{
my.get(number+"");
},"Thread"+String.valueOf(i)).start();
}
}
}
//无锁
class NoLockTest{
private volatile Map<String,String> map = new HashMap<>();
//存
public void put(String key,String value){
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕");
}
//取
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取"+key);
String value = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完毕");
}
}
结果:
线程2在写入的时候被插队了,因此就导致线程2还没有写完就被线程1强行写进来了,这样做很明显不符合逻辑。
二:有锁案例
这里的锁并没有使用一般的Lock中的可重入锁,因为Lock锁虽然也能实现线程的有序进行,但lock会将内容直接就给单线程锁死了,可这里针对于map变量的操作情况是:在put数据的时候需要加锁使其有序进行;在get数据的时候无序强调有序进行,因为get操作只牵扯到数据的读取,数据本身不会被改变,因此允许多线程操作反而会有更高的效率。
public class RW {
public static void main(String[] args) {
LockTest my = new LockTest();
//存
for (int i = 1; i <=10 ; i++) {
final Integer number = i;
new Thread(()->{
my.put(number+"",number+"");
},"Thread"+String.valueOf(i)).start();
}
//取
for (int i = 1; i <=10 ; i++) {
final Integer number = i;
new Thread(()->{
my.get(number+"");
},"Thread"+String.valueOf(i)).start();
}
}
}
//加锁
class LockTest{
private volatile Map<String,String> map = new HashMap<>();
//读写锁
private ReadWriteLock lock = new ReentrantReadWriteLock();
//存,一次只允许一个线程操作
public void put(String key,String value){
lock.writeLock().lock();//独占锁
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();//解锁
}
}
//取,一次可允许多个线程操作
public void get(String key){
lock.readLock().lock();//共享锁
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
String value = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完毕");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();//释放锁
}
}
}