JUC之锁的问题和集合的使用
1.锁的应用
Java提供了各种各样的锁,每种锁因其特性的不同,在适当的场景或者能够展现出非常高的效率、或者解决安全问题,本文主要从和安全方面进行阐述。
2.锁的对象
2.1 synchronized锁的对象是方法的调用者,同一个对象,调用不同方法,谁先拿到锁,谁先执行;
2.2 如果是普通方法,则不受锁的影响,如果一起执行,synchronized的方法有延迟则,会优先执行普通方法;
2.3 synchronized锁的对象是方法的调用者,当有两个对象调用方法一起执行的时候,是有两把锁和两个调用者,这时候执行是按照时间来执行,有延迟的后执行;
2.4 当两个静态方法一起执行的时候,static修饰,时无论有多少个对象,由于一个类只有一个Class反射对象,全局唯一,所以依然是,谁先拿到锁,谁先执行;
2.5 当一个普通同步方法和一个静态方法一起执行的时候,由于锁的不同对象,普通同步方法锁的是对象(可以有很多个),而静态方法锁的是Class对象(全局只有一个),所以是按照延迟的时间来判断是谁先执行的;
3.集合的使用
集合在单个线程中使用时,基本不会出现并发异常问题,但是如果在执行多线程的时候,经常要处理并发异常,下面就是一个经常出现的集合异常,并发修改异常:
Exception in thread "1" java.util.ConcurrentModificationException
3.1 解决集合并发的方法
3.1.1 使用Vector实现类
为什么使用Vector实现类会解决集合中的多线程安全问题,ArrayList实现类为什么会有出现并发修改异常这类多线程安全问题呢?
首先,我们查看一下List接口中的add方法,发现有许多实现方法,找到Vector和ArrayList中的不同实现来进行阐述:
Vector中的add方法,因为加了synchronized同步锁,所以在多线程执行的时候,始终是线程安全的,但也牺牲了效率;
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
而ArrayList中的add方法,并没有增加锁,保持了高效率,在单线程的时候基本不会出现问题,但是遇到多线程的时候,就会出现线程安全的问题了。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
3.1.2 使用Collections工具类下的同步方法
Collections是一个工具类,不能被实例化,提供了许多强大而丰富的集合相关的静态方法,其中就包括处理集合中的线程安全问题的各种同步方法,例如:
Collections.synchronizedList(new ArrayList<>());

3.1.3 JUC中的CopyOnWriteArrayList
查看CopyOnWriteArrayList方法的构造方法会发现,底层是用transient volatile修饰的数组,这些正是保证线程安全的所在;
CopyOnWriteArrayList方法是一种采用读写分类,在写入时复制,完全后再赋值的策略;
例如:对数据A进行写入操作
3.1.3.1 复制A==》A1;
3.1.3.2 完成写入操作,即对A1进行修改操作;
3.1.3.3 再将修改后的A1复制给A;
3.1.3.4 如果在完成写入过程中,有人要读取数据A,则写入操作并不会影响到读取,读的还是原来的数据A,当写入完成后才会修改A为A1,这时候读取的就是新的数据A1的值,避免了读取数据异常的问题;
再完全写入后将数据赋值给原数据,在此期间如果有人读取数据
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
final void setArray(Object[] a) {
array = a;
}
private transient volatile Object[] array;
CopyOnWriteArrayList同样是List接口的实现类,其中实现的add方法,并没有使用synchronized同步锁也就不会影响效率,而是使用的Lock锁进行加锁,处理业务,解锁的操作;
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
- 点赞
- 收藏
- 关注作者
评论(0)