Java并发集合操作中对锁的应用。

下面以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

可以看到读锁在不同的线程中是不排斥的。好的,就为大家介绍到这里。

时间: 2024-10-16 11:14:04

Java并发集合操作中对锁的应用。的相关文章

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

java - 并发集合 Vector、synchronizedCollection、CopyOnWriteArrayList之间的区别。

概要 JDK中提供ArrayList集合方便我们对集合内元素进行增删改查,但是ArrayList为了能够在单线程中快速进行操作其设计并不支持多线程进行操作.ArrayList在多线程环境下可能会产生java.util.ConcurrentModificationException异常.而对于我们需要在多线程下操作集合Jdk为我们内置了支持多线程操作的并发集合类供我们使用. Vector Vector始于JDK1.0版本而ArrayList始于JDK1.2版本.Vector对于每个对集合操作的方法

Java 并发:内置锁 Synchronized

摘要: 在多线程编程中,线程安全问题是一个最为关键的问题,其核心概念就在于正确性,即当多个线程访问某一共享.可变数据时,始终都不会导致数据破坏以及其他不该出现的结果.而所有的并发模式在解决这个问题时,采用的方案都是序列化访问临界资源 .在 Java 中,提供了两种方式来实现同步互斥访问:synchronized 和 Lock.本文针对 synchronized 内置锁 详细讨论了其在 Java 并发 中的应用,包括它的具体使用场景(同步方法.同步代码块.实例对象锁 和 Class 对象锁).可重

Java并发集合(一)-CopyOnWriteArrayList分析与使用

原文链接: http://ifeve.com/java-copy-on-write/ 一.Copy-On-Write Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWrite

Java并发编程之StampedLock锁源码探究

StampedLock是JUC并发包里面JDK1.8版本新增的一个锁,该锁提供了三种模式的读写控制,当调用获取锁的系列函数的时候,会返回一个long 型的变量,该变量被称为戳记(stamp),这个戳记代表了锁的状态. try系列获取锁的函数,当获取锁失败后会返回为0的stamp值.当调用释放锁和转换锁的方法时候需要传入获取锁时候返回的stamp值. StampedLockd的内部实现是基于CLH锁的,CLH锁原理:锁维护着一个等待线程队列,所有申请锁且失败的线程都记录在队列.一个节点代表一个线程

JAVA并发编程学习笔记------锁顺序死锁

一.需求描述: 将资金从一个账户转移到另一个账户. 二.程序实现: (1)账户类: public class Account { private long account; public Account(String user, long account) { this.account = account; } public Account() { super(); } public long getAccount() { return account; } public void setAcc

Java并发编程与技术内幕:聊聊锁的技术内幕(上)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.基础知识 在Java并发编程里头,锁是一个非常重要的概念.就如同现实生活一样,如果房子上了锁.别人就进不去.Java里头如果一段代码取得了一个锁,其它地方再想去这个锁(或者再执行这个相同的代码)就都得等待锁释放.锁其实分成非常多.比如有互斥锁.读写锁.乐观锁.悲观锁.自旋锁.公平锁.非公平锁等.包括信号量其实都可以认为是一个锁. 1.什么时需要锁呢? 其实非常多的场景,如共享实例变量.共

Java并发3-多线程面试题

1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. 2) 线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务.不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间.别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据. 3) 如何在Java中实现线程? 在语言层面有两种方式.java.lang.Thread

1.java并发-启程

1.java并发-启程 看了差不多快一个月的 java 并发有关的知识点了,看的比较多的是这个博主的死磕java系列 写的很好,感谢! 但是不写下来的话感觉忘得很快,趁现在有时间,多写点东西吧! 1. 为什么需要Java并发? 在大学学习 Java 的时候虽然也学了一点与线程有关的内容,但在实操中并没有使用到什么.虽然也做了课设,但是基本上不会被使用,所以也不会去关注程序的并发性问题,因为根本不会出现这样的问题.但是一个产品要投入使用,在生产中就不得不考虑了.单线程是不可能满足企业的业务需求的,