线程安全与锁优化——深入理解Java虚拟机

线程安全与锁优化

一、线程安全

1.Java语言中的线程安全——对共享数据的操作

按照线程安全的”安全强度”由强到弱排序,Java语言中各项操作共享的数据分为不可变、绝对线程安全、相对线程安全、线程兼容、线程对立

(a)不可变

不可变对象一定是线程安全的。如果共享数据是基本数据类型,那么只要在定义时使用final关键字修饰它保证是不可变的;如果共享数据是对象,则需要保证对象的行为不会对其状态产生任何影响

private final int value;

public Integer(int value){
    this.value = value;
}

实例: String Long Integer…

(b)绝对线程安全

符合绝对线程安全的定义。

(c)相对线程安全

我们通常意义上的线程安全。需要保证对这个对象单独的操作是线程安全的,在调用的时候不需要做额外的保障措施。如Vector、HashTable等。

(d)线程兼容

指对象本身并不是线程安全的,但是可以通过在调用端正确的使用同步手段来保证对象在并发情况下可以安全的使用。如ArrayList、HashMap。

(e)线程对立

无论调用端是否采取了同步措施,都无法在多线程环境中并发使用。

2.线程安全的实现方式

(a)同步互斥

同步指在多个线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程使用。互斥是实现同步的一种手段,临界区、互斥量、信号量是实现互斥量的实现方式。

①Java中最基本的互斥同步手段即synchronized关键字,同步代码块前后形成字节码(monitorenter、monitorexit)。并且同一线程可重入。

②ReentrantLock重入锁

相比于synchronized, 增加了高级功能:

  • 等待可中断

    当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他的事情。

  • 可实现公平锁

    多个线程在等待同一个锁时,必须按照申请所得时间顺序来依次获取锁。synchronized是非公平锁,ReentrantLock默认是非公平锁,但可以设置使用公平锁。

  • 锁可以绑定多个条件。

    一个 ReentrantLock对象可以同时绑定多个Condition对象。

(b)非阻塞同步

①互斥同步手段是一种悲观的并发策略,性能消耗很大。—阻塞同步
②基于冲突检查的乐观并发策略,指先进行操作,如果没有其他线程争用共享数据,那操作成功;如果共享数据有争用,产生了冲突,那就再采取其他补偿措施(如不断地重试,直到成功)。—–非阻塞式同步

乐观机制需要硬件指令集的支持,硬件保证一个看起来需要多次操作的行为只通过一个处理器指令就能完成,如

  • 测试并设置(Test-and-Set)
  • 获取并增加(Fetch-and-Increment)
  • 交换(Swap)
  • 比较并交换(CAS)
  • 加载链接/条件存储(Load-Linked/Store-Conditional, LL/SC)

线程安全与锁优化——深入理解Java虚拟机_第1张图片

以下是CAS在JDK中的应用(AtomicInteger.incrementAndGet())

public final int incrementAndGet(){
    for(;;){
        int current = get(); 
        int next = current + 1;
        if(compareAndSet(current, next)){
            return next;
        }
    }
}

incrementAndGet()方法在一个无限循环中,不断尝试将一个比当前值大1的新值赋给自己。如果失败了,说明在执行”获取-设置”的时候已经有了修改,就循环重试,直到成功。

(c)无同步方案

ThreadLocal线程本地变量

二、锁优化—自旋锁、锁消除、锁粗化、轻量级所、偏向锁

你可能感兴趣的:(JVM虚拟机,Java多线程,Java基础)