Kuangcp/JavaBase

View on GitHub
concurrency/src/main/java/com/github/kuangcp/list/CopyOnWriteDemo.java

Summary

Maintainability
A
0 mins
Test Coverage
package com.github.kuangcp.list;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by https://github.com/kuangcp on 17-8-15  上午9:41
 *
 * CopyOnWriteList 的应用案例
 * 迭代时加锁 保证了此次迭代过程不受影响,但是读取到的数据并不是实时的,
 * 而是读取加锁那一刻的数据快照,这就会导致每次读取的数据都可能不同
 *
 * 这里的锁加不加无所谓,因为他们是各自读取的副本 因为这个类的特性,不加锁也能正常运行,
 * 没有并发读取的事情发生,加不加锁都会出现只有第二个线程有输出的现象:
 * 为什么只有第二个线程有输出??? 加不加锁都会出现的问题就是获取的迭代器是同一个对象,
 * 因为多线程的情况下调用同一个方法会有这种情况,因为不同步,所以还是要加上关键字么???
 *
 * *****************************
 * 不加锁的情况下  这是个什么输出???? 猜测是因为线程的竞争,同时输出的结果
 * 猜测是 先是输出了名字,然后应该输出换行的时候,被第二个线程抢占了输出,然后输出了第一个元素后,该线程输出的换行,然后输出了第二个线程的所有的信息就结束了
 * a: a: Element{phone='2'}, Element{phone='3'}, Element{phone='4'}, Element{phone='5'},
 * Element{phone='1'},
 *
 * 这是按正常的思路运行正常的结果,这个类就以这两种结果,交替输出。。。。。。
 * a: Element{phone='1'}, Element{phone='2'}, Element{phone='3'}, Element{phone='4'},
 * a: Element{phone='1'}, Element{phone='2'}, Element{phone='3'}, Element{phone='4'}, Element{phone='5'},
 * *************************
 * 加锁的情况下的 怪异输出是这样的,和上面的不加锁的信息一致,但是顺序乱了,说明了锁 保证了两个线程的先后性
 * a: Element{phone='1'}, Element{phone='2'}, Element{phone='3'}, Element{phone='4'}, Element{phone='5'},
 * a:
 *
 *
 * 这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法更 有效。在不能或不想进行同步遍历,
 * 但又需要从并发线程中排除冲突时,它也很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,
 * 因此不可能发生冲突,并且迭代器保证不会抛出 ConcurrentModificationException。创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。
 * 在迭代器上进行的元素更改操作(remove、set 和 add)不受支持。这些方法将抛出 UnsupportedOperationException。
 *
 *
 * 如果在迭代输出的过程中,加上睡眠时间,猜测 第二个线程就因为锁没有释放得不到数据,锁失败了就放弃了,不等待么
 * 可是锁成功了呀??? 是迭代器获取失败?
 * 原来得到的是一个迭代器。。因为迭代器是单向指针,迭代一次就无法再次使用了,
 * 所以拿到迭代器的第二次想要迭代的线程 当然是没有数据的,
 */
public class CopyOnWriteDemo {

    public static void main(String[] s) {
        CopyOnWriteArrayList<Element> elements = new CopyOnWriteArrayList<>();
        ReentrantLock lock = new ReentrantLock();
        ElementList<Element> list = new ElementList<>(elements, lock, "list > ");

        // 两个独立的线程分别加锁并得到了副本,所以运行得到的结果是不同的
        new Thread(() -> {
            list.addElement(new Element("1"));
            list.addElement(new Element("2"));
            list.addElement(new Element("3"));
            list.addElement(new Element("4"));
            list.prep();
            list.listElement("th1 : ");
        }).start();

        new Thread(() -> {
            list.addElement(new Element("5"));
            list.prep();
            list.listElement("th2 : ");
        }).start();

    }
}