总结-2020.6.1~6.6

1.JSR-303 @Valid验证引发BindException异常还是MethodArgumentNotValidException异常

1.当使用@Valid不带@RequestBody request参数时,当对象验证失败时,验证将引发BindException而不是MethodArgumentNotValidException。
2.当你@valid 带@RequestBody 时候是 MethodArgumentNotValidException。

小结:所以在进行全局异常处理的时候,你注意你应该用什么异常,不确定的时候,一起加入全局异常。
@ExceptionHandler(value = BindException.class)
@ExceptionHandler(value = MethodArgumentNotValidException.class)

2.自定义校验

第一步:
在这里插入图片描述
第二步:
在这里插入图片描述
第三步:
在这里插入图片描述
引入:
https://www.cnblogs.com/sanboshi/p/9378666.html

3.多线程 arrayList() 安全问题

现在有个简单的需求,就是多个线程,对同一个list 集合进行add操作。代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 解决安全问题的替换方法
 * 1.vector
 * 2.synchronizedList(new ArrayList)
 * 3.CopyOnWriteArrayList
 */
public class NoSafe {
    public static void main(String[] args) throws Exception {

        List<String> list = new ArrayList<>();
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            executorService.execute(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(list);
                latch.countDown();
            });
        }
        latch.await();
        System.out.println(list);
        executorService.shutdown();
    }
}

打印结果
[77cda994, 530023fa]
[77cda994, 530023fa]
[77cda994, 530023fa]
[77cda994, 530023fa]

数据不对。
有时候还会有ConcurrentModificationException 阻塞异常

解决方案,将arrayList 替换为。
1.new vector()
2.new synchronizedList(new ArrayList)
3.new CopyOnWriteArrayList()

4.synchronized 的操作范围

  1. 锁同一个对象时候,如果这个对象多个方法有synchronized 时候都会被影响。这个对象的普通方法不会受影响。
  2. Synchronized如果锁的是static 方法,则这个对象对应的class ,其他实例其他static synchronized方法都会被影响。Synchronized(synchronized 与static synchronized 相当于两帮派,各自管各自,相互之间就无约束了) 和普通方法不会被影响。

5.CopyOnWriteArrayList

写入时复制(CopyOnWrite)思想
  写入时复制(CopyOnWrite,简称COW)思想是计算机程序设计领域中的一种优化策略。其核心思想是,如果有多个调用者(Callers)同时要求相同的资源(如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者视图修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此做法主要的优点是如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。
说白了,就是读写分离,等写完了(写的过程加锁,读不受影响,读还是读的旧的对象),将新对象引用,旧对象删除。
CopyOnWriteArrayList的实现原理
  在使用CopyOnWriteArrayList之前,我们先阅读其源码了解下它是如何实现的。以下代码是向CopyOnWriteArrayList中add方法的实现(向CopyOnWriteArrayList里添加元素),可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。

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

读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。实现读写分离,直到写完了,会把旧对象直接= 给 新对象。这样读很快,但一次写会Arrays.copyOf 新的数组对象,消耗内存多,所以建议读操作多的可以使用这个集合保证线程安全。

读操作
public E get(int index) {
    return get(getArray(), index);
}

JDK中并没有提供CopyOnWriteMap,我们可以参考CopyOnWriteArrayList来实现一个,基本代码如下:

import java.util.Collection;
import java.util.Map;
import java.util.Set;
 
public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
    private volatile Map<K, V> internalMap;
 
    public CopyOnWriteMap() {
        internalMap = new HashMap<K, V>();
    }
 
    public V put(K key, V value) {
 
        synchronized (this) {
            Map<K, V> newMap = new HashMap<K, V>(internalMap);
            V val = newMap.put(key, value);
            internalMap = newMap;
            return val;
        }
    }
 
    public V get(Object key) {
        return internalMap.get(key);
    }
 
    public void putAll(Map<? extends K, ? extends V> newData) {
        synchronized (this) {
            Map<K, V> newMap = new HashMap<K, V>(internalMap);
            newMap.putAll(newData);
            internalMap = newMap;
        }
    }
}

引用:https://www.cnblogs.com/myseries/p/10877420.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值