多线程中对某些共享变量进行读写操作,并发读操作时不会产生问题,并发读写或并发写操作会引起线程安全性问题。
下面代码会报错:java.util.ConcurrentModificationException
public class TestReentrantReadWriteLock {
volatile Map dataMap = new HashMap();
private static TestReentrantReadWriteLock testReentraintReadWriteLock = new TestReentrantReadWriteLock();
private static TestReentrantReadWriteLock getInstace(){
return testReentraintReadWriteLock;
}
public void readMap(){
Map refMap = dataMap;
Iterator iterator = refMap.keySet().iterator();
while(iterator.hasNext()){//这行报错:java.util.ConcurrentModificationException
Object key = iterator.next();
Object value = refMap.get(key);
}
}
public void writeMap(){
dataMap.clear();
for(int i=0;i<100;i++){
dataMap.put(i+"", i+"");
}
}
public static void main(String args []){
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub\
while(true){
TestReentrantReadWriteLock.getInstace().readMap();
}
}
}).start();
}
for(int i=0;i<1;i++){
new Thread(new Runnable(){
@Override
public void run() {
while(true){
TestReentrantReadWriteLock.getInstace().writeMap();
}
}
}).start();
}
}
}
解决方法:
1 如果只有一条线程会执行写操作, 可以在写操作时新建一个MAP(业务逻辑上可行的话),然后替换原来的MAP:
public void writeMap(){
Map newMap = new HashMap();
for(int i=0;i<100;i++){
newMap.put(i+"", i+"");
}
dataMap = newMap;
}
1.使用java.util.concurrent.ConcurrentHashMap 代替HashMap 解决问题。
2.使用synchronized 锁,需要加到 writeMap 和 readMap方法上,可以决问题,但多个读操作互斥,影响并发。
3.读操作远大于写操作情况下可以使用ReentrantReadWriteLock
示例代码:
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public void readMap(){
rwl.readLock().lock();//读取锁 读取与读取可并发,与写入互斥
try{
Map refMap = dataMap;
Iterator iterator = refMap.keySet().iterator();
while(iterator.hasNext()){
Object key = iterator.next();
Object value = refMap.get(key);
}
}finally{
rwl.readLock().unlock();//解锁
}
}
public void writeMap(){
rwl.writeLock().lock();//写入锁 写入与读取之间互斥 写入与写入之间互斥
try{
dataMap.clear();
for(int i=0;i<100;i++){
dataMap.put(i+"", i+"");//解锁
}
}finally{
rwl.writeLock().unlock();
}
}