JUC之锁的问题和集合的使用

举报
多米诺的古牌 发表于 2021/08/18 22:35:52 2021/08/18
【摘要】 1.锁的应用Java提供了各种各样的锁,每种锁因其特性的不同,在适当的场景或者能够展现出非常高的效率、或者解决安全问题,本文主要从和安全方面进行阐述。2.锁的对象2.1 synchronized锁的对象是方法的调用者,同一个对象,调用不同方法,谁先拿到锁,谁先执行;2.2 如果是普通方法,则不受锁的影响,如果一起执行,synchronized的方法有延迟则,会优先执行普通方法;2.3 syn...

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();
    }
}

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。