Java并发集合操作中对锁的应用
来源:互联网 发布:linux cp 合并文件夹 编辑:程序博客网 时间:2024/06/05 00:47
摘要: 通过锁解决在不同线程读取和修改集合引发的问题。
下面以List结合为例子,
先来看以下代码:
public static ArrayList<String>datas=new ArrayList<String>();
//初始化数据
public static void initData(){
for(int i=0;i<20;i++){
datas.add(""+i);
}
}
//线程1,读取集合的数据
public static Thread thread1=new Thread(){
public void run() {
//int size=datas.size();
for(String data:datas){
System.out.println(data);
}
};
};
//线程2,删除集合的数据
private static Thread thread2=new Thread(){
public void run() {
int size=datas.size();
for(int i=0;i<size;i++){
datas.remove(0);
System.out.println("remove");
}
};
};
//启动程序
public static void main(String[] args) {
initData();
thread1.start();
thread2.start();
}
这样子运行的话,肯定会出一个异常。下面请看执行的结果
remove
remove
1
remove
remove
remove
remove
remove
remove
Exception in thread "Thread-0" remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
在现实编程环境中,经常会遇到既需要遍历集合,又需要在另一个线程中删除集合。那么怎么解决呢?
下面就来解决这个问题,我们用到了位于java.util.concurrent.locks包里面的ReentrantReadWriteLock;
简称读写锁,它有两个核心的方法,分别是readLock()和writeLock(),即获取读锁和写锁。获取读锁的前提是写锁没有锁住。获取写锁的前提是读锁没有锁住。也就是保证在读的时候就没有人在写数据或者修改数据。在写数据或者修改数据的时候就没有人在读数据。就好像我们编辑word文档一样,在编辑状态,就不允许移动,复制。根据这个原理,我们接下来改进代码如下:
public static final ReadWriteLock lock = new ReentrantReadWriteLock(false);
public static ArrayList<String>datas=new ArrayList<String>();
public static void initData(){
for(int i=0;i<20;i++){
datas.add(""+i);
}
}
public static Thread thread1=new Thread(){
public void run() {
lock.readLock().lock();
for(String data:datas){
System.out.println("t1 "+data);
}
lock.readLock().unlock();
};
};
public static Thread thread3=new Thread(){
public void run() {
lock.readLock().lock();
for(String data:datas){
System.out.println("t3 "+data);
}
lock.readLock().unlock();
};
};
private static Thread thread2=new Thread(){
public void run() {
int size=datas.size();
lock.writeLock().lock();
for(int i=0;i<size;i++){
datas.remove(0);
System.out.println("remove");
}
lock.writeLock().unlock();
};
};
public static void main(String[] args) {
initData();
thread1.start();
thread2.start();
thread3.start();
}
这时候程序执行结果是:
t1 0
t1 1
t1 2
t1 3
t1 4
t1 5
t1 6
t1 7
t1 8
t1 9
t1 10
t1 11
t1 12
t1 13
t1 14
t1 15
t1 16
t1 17
t1 18
t1 19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
大家可能疑惑为啥没有t3的打印呢?因为读锁在释放之后,立马就被写锁占用了,写锁的线程把集合清空了,所以当轮到线程3的时候就没有数据了,多试几次,会发现还有一种执行结果就是全部都是remove。没有任何打印,这是因为先执行了线程2的缘故。如果我们按照这样的顺序执行,又会不同:
public static void main(String[] args) {
initData();
thread1.start();
thread3.start();
thread2.start();
}
t3 0
t1 0
t3 1
t1 1
t3 2
t1 2
t3 3
t1 3
t3 4
t1 4
t3 5
t1 5
t3 6
t1 6
t3 7
t1 7
t3 8
t1 8
t3 9
t1 9
t3 10
t1 10
t3 11
t1 11
t3 12
t1 12
t3 13
t1 13
t3 14
t1 14
t3 15
t1 15
t1 16
t1 17
t3 16
t1 18
t1 19
t3 17
t3 18
t3 19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
可以看到读锁在不同的线程中是不排斥的。好的,就为大家介绍到这里。
下面以List结合为例子,
先来看以下代码:
public static ArrayList<String>datas=new ArrayList<String>();
//初始化数据
public static void initData(){
for(int i=0;i<20;i++){
datas.add(""+i);
}
}
//线程1,读取集合的数据
public static Thread thread1=new Thread(){
public void run() {
//int size=datas.size();
for(String data:datas){
System.out.println(data);
}
};
};
//线程2,删除集合的数据
private static Thread thread2=new Thread(){
public void run() {
int size=datas.size();
for(int i=0;i<size;i++){
datas.remove(0);
System.out.println("remove");
}
};
};
//启动程序
public static void main(String[] args) {
initData();
thread1.start();
thread2.start();
}
这样子运行的话,肯定会出一个异常。下面请看执行的结果
remove
remove
1
remove
remove
remove
remove
remove
remove
Exception in thread "Thread-0" remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
在现实编程环境中,经常会遇到既需要遍历集合,又需要在另一个线程中删除集合。那么怎么解决呢?
下面就来解决这个问题,我们用到了位于java.util.concurrent.locks包里面的ReentrantReadWriteLock;
简称读写锁,它有两个核心的方法,分别是readLock()和writeLock(),即获取读锁和写锁。获取读锁的前提是写锁没有锁住。获取写锁的前提是读锁没有锁住。也就是保证在读的时候就没有人在写数据或者修改数据。在写数据或者修改数据的时候就没有人在读数据。就好像我们编辑word文档一样,在编辑状态,就不允许移动,复制。根据这个原理,我们接下来改进代码如下:
public static final ReadWriteLock lock = new ReentrantReadWriteLock(false);
public static ArrayList<String>datas=new ArrayList<String>();
public static void initData(){
for(int i=0;i<20;i++){
datas.add(""+i);
}
}
public static Thread thread1=new Thread(){
public void run() {
lock.readLock().lock();
for(String data:datas){
System.out.println("t1 "+data);
}
lock.readLock().unlock();
};
};
public static Thread thread3=new Thread(){
public void run() {
lock.readLock().lock();
for(String data:datas){
System.out.println("t3 "+data);
}
lock.readLock().unlock();
};
};
private static Thread thread2=new Thread(){
public void run() {
int size=datas.size();
lock.writeLock().lock();
for(int i=0;i<size;i++){
datas.remove(0);
System.out.println("remove");
}
lock.writeLock().unlock();
};
};
public static void main(String[] args) {
initData();
thread1.start();
thread2.start();
thread3.start();
}
这时候程序执行结果是:
t1 0
t1 1
t1 2
t1 3
t1 4
t1 5
t1 6
t1 7
t1 8
t1 9
t1 10
t1 11
t1 12
t1 13
t1 14
t1 15
t1 16
t1 17
t1 18
t1 19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
大家可能疑惑为啥没有t3的打印呢?因为读锁在释放之后,立马就被写锁占用了,写锁的线程把集合清空了,所以当轮到线程3的时候就没有数据了,多试几次,会发现还有一种执行结果就是全部都是remove。没有任何打印,这是因为先执行了线程2的缘故。如果我们按照这样的顺序执行,又会不同:
public static void main(String[] args) {
initData();
thread1.start();
thread3.start();
thread2.start();
}
t3 0
t1 0
t3 1
t1 1
t3 2
t1 2
t3 3
t1 3
t3 4
t1 4
t3 5
t1 5
t3 6
t1 6
t3 7
t1 7
t3 8
t1 8
t3 9
t1 9
t3 10
t1 10
t3 11
t1 11
t3 12
t1 12
t3 13
t1 13
t3 14
t1 14
t3 15
t1 15
t1 16
t1 17
t3 16
t1 18
t1 19
t3 17
t3 18
t3 19
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
remove
可以看到读锁在不同的线程中是不排斥的。好的,就为大家介绍到这里。
阅读全文
0 0
- Java并发集合操作中对锁的应用
- 对Java中常用集合的操作
- java中对集合List的操作
- Java中对集合的并,交,联集,差操作
- 在JAVA中,对List集合的加减操作
- Java中对List集合的常用操作
- Java中对List集合的常用操作
- java中对List集合的常用操作
- 在JAVA中,对List集合的加减操作
- Java中对List集合的常用操作
- Java中对List集合的常用操作
- java中并发集合
- JAVA对DataSet的操作大集合
- JAVA集合的并发
- 关于java集合的遍历以及ConcurrentModificationException(并发操作异常)
- java中List的并发操作
- Java中对Array数组的常用操作,交集并集合集!
- Java集合类中TreeMap的应用
- Java之异常
- Linux C 多线程编程 互斥锁
- 杭电acm 1171Big Event in HDU(0-1背包)
- 【HDU 1016】Prime Ring Problem(DFS、素数筛)
- 2017云哥性能测试实战带你走出迷茫
- Java并发集合操作中对锁的应用
- Python学习之文件处理详解
- Java表格仿mysql实现基本操作(连接,分组排序,统计等)
- Linux C 多线程编程条件变量
- [第五季]14.属性选择器和伪类伪元素
- 美团js面试题
- 下一阶段的一些想法
- Mysql中的MVCC
- miui8.5开发者选项USB调试模式