Thread的Start()方法并不是立即启动,而是就绪状态,等待底层cpu的调度/** * 1 故障观象 * java.util.ConcurrentModificationException * 2 导致原因 * 多线程并发争抢统一资源,没有锁 * 3 解决方法 * 3.1 new vector<>() * 3.2 collections.synchronizedList(new Arraylist<>()); * 3.3 new CopyOnWriteArrayList() 写时复制,读写分离的体现 * copyonwrite 容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器bject[]添加, * 而是先将当前容器Object[]进行copy,复制出一个新的容器Object[] newELements, * 然后新的容器Object[] newELements里添加元素,添加完元素之后, * 再将原容器的引用指同新的容器 setArray(newELements);。 * 这样做的好处是可以对CopyOnwrite容器进行并发的读, * 而不需要加锁,因为当前容器不会添加在任何元素。 * 所以copyOnwrite容器也是一种读写分离的思想,读和写不同的容器 */public class NotSafeDemo03 { public static void main(String[] args) { //listNotSafe(); //setNotSafe(); Map<Object, Object> map = new ConcurrentHashMap<>(); for(int i =1 ;i <=30;i++){ new Thread(() -> { map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,3)); System.out.println(map); },String .valueOf(i)).start(); } } public static void setNotSafe() { Set<String> list = new CopyOnWriteArraySet<>(); for(int i =1 ;i <=30;i++){ new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0,3)); System.out.println(list); },String .valueOf(i)).start(); } } public static void listNotSafe() { //List<String> list = Collections.synchronizedList(new ArrayList<>()); List<Object> list = new CopyOnWriteArrayList<>(); for(int i =1 ;i <=30;i++){ new Thread(() -> { list.add(UUID.randomUUID().toString().substring(0,3)); System.out.println(list); },String .valueOf(i)).start(); } }} 锁的问题
一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线理去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刺内,只能有唯一一个线程去访问这些synchronized方法。
锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法。
加个普通方法后发现和同步锁无关。
换成两个对象后,不是同一把锁了,情泥立刻变化。
synchronized实规同步的基础:Java中的每一个对象都可以作为锁。
具体衣现为以下3种形式。
对于普通同步方法,锁是当前实例对象。
对于同步方法块,锁是synchonized括号里配置的对象。
对于静态同步方法,锁是当前类的Class对象。
- 当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出时异常必须释放锁。
也就是说如果一个实例可象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁。
- 可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
- 所有的静态同步方法用的也是同一把锁一类对象Class本身。
这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞争条件的。
- 但是一旦一个静态同步方法获取锁后,其他的静态同步方法部必须等待该方法释放锁后才能获取锁。
而不是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
|