并发--先行发生原则及案例分析

并发–先行发生原则及案例分析

标签(空格分隔): Java-JVM


先行发生原则

先行发生原则是判断数据是否存在竞争、线程是否安全的主要依据。

  1. 程序次序规则(Program Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
  2. 管程锁定规则(Monitor Lock Rule):一个unlock操作先行发生于后面对于同一个锁的lock操作。这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。
  3. volatile变量规则(Volatile Variable Rule):对于一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”同样是指时间的先后顺序。
  4. 线程启动规则(Thread Start Rule):Thread对象的start()方法先行发生于此线程的每一个动作。
  5. 线程终止规则(Thread Termination Rule):线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
  6. 线程中断规则(Thread Interrupt Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
  7. 对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
  8. 传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。

摘自:《深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)》


案例分析(1)–线程安全类Vector

线程安全类型Vector,只是相对线程安全,并非绝对线程安全

private static Vector<Integer> vector = new Vector<Integer>();

public static void main(String[] args) {
    while (true) {
        for (int i = 0; i < 10; i++) {
            vector.add(i);
        }

    Thread removeThread = new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i < vector.size(); i++) {
                vector.remove(i);
            }
        }
    });

    Thread getThread = new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i < vector.size(); i++) {
//          尝试加入首先判断i是否在vector size范围内,结果同样报错,
//              if (i < vector.size()) {
//                  continue;
//              }
                vector.get(i);
            }
        }
    });

    removeThread.start();
    getThread.start();

    //不要同时产生过多的线程,否则会导致操作系统假死
        while (Thread.activeCount() > 20) ;
    }
}
  1. 程序次序:不满足,remove(i)get(i)在控制流顺序没有先行发生关系;
  2. 管程锁定:不满足,remove(i)get(i)方法都是synchronized修饰,但各自持有不同的锁,不满足管程锁定要求的同一个锁;
  3. volatile变量:不满足,没有volatile修饰变量,无视;
  4. 线程启动:不满足,removeThread.start()先与vector.remove(i)getThread.start()先于vector.get(i),但后两者明显没有关系;
  5. 线程终止:不满足;
  6. 线程中断:不满足;
  7. 对象终结:不满足,不存在对象终结的关系;
  8. 传递性:不满足,加入size()验证作为参考,假定A是remove(),B是size()验证,C是get(),B先于C,但A可能介乎于BC之间,也可能在B之前。因此不符合传递性。

结论:Vector作为相对线程安全对象,其单个方法带Synchronized修饰,是相对线程安全的,但Vector方法之间不是线程安全的,不能保证多个方法作用下的数据一致性。执行例子get()会报错:java.lang.ArrayIndexOutOfBoundsException

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值