Java concurrent包源码走读(一)

为了更好的走读Java concurrent包源码,首先普及下基础知识:volatile、CAS、LockSupport。

concurrent包的实现示意图

Java concurrent包源码走读(一)_第1张图片

volatile

  1. 保证可见性,但是不保证原子性(i++并发出问题)

  2. 禁止指令重排序
    指令重排序推荐阅读

CAS

简介

CAS(Compare And Swap))顾名思义为比较并交换。CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了 “ 我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”

目的

利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。

问题

  1. ABA问题
    如果V的值先由A变成B,再由B变成A,我们最终看到的是A,但是是发生变化了。我们可以通过加时间戳或者版本号来解决。

  2. 循环时间长开销大
    如果JVM能支持处理器提供的pause指令那么效率会有一定的提升。

  3. 只能保证一个共享变量的原子操作
    我们可以通过把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。

温馨提示:感兴趣的同学可以通过AtomicInteger等原子类源码来了解CAS的具体实践

LockSupport

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。每个使用LockSupport的线程都会与一个许可关联,如果该许可可用,并且可在进程中使用,则调用park()将会立即返回,否则可能阻塞。如果许可尚不可用,则可以调用 unpark 使其可用。但是注意许可不可重入,也就是说只能调用一次park()方法,否则会一直阻塞。

LockSupport问题

  1. LockSupport.park()和unpark(),与object.wait()和notify()的区别?

    1.1 面向的主体不一样。LockSuport主要是针对Thread进进行阻塞处理,可以指定阻塞队列的目标对象,每次可以指定具体的线程唤醒。Object.wait()是以对象为纬度,阻塞当前的线程和唤醒单个(随机)或者所有线程。

    1.2 实现机制不同。虽然LockSuport可以指定monitor的object对象,但和object.wait(),两者的阻塞队列并不交叉。可以看下测试例子。object.notifyAll()不能唤醒LockSupport的阻塞Thread.

  2. LockSupport能响应Thread.interrupt()事件不?会抛出InterruptedException异常?
    能响应interrupt事件,但不会抛出InterruptedException异常。

//问题2
public class LockSupportInterrupt {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            private int count = 0;
            @Override
            public void run()
            {
                long start = System.currentTimeMillis();
                long end = 0;

                while ((end - start) <= 1000)
                {
                    count++;
                    end = System.currentTimeMillis();
                }

                System.out.println("after 1 second.count=" + count);

                //等待或许许可
                LockSupport.park();
                System.out.println("thread over." + Thread.currentThread().isInterrupted());

            }
        });

        t.start();
        Thread.sleep(2000);
        // 中断线程
        t.interrupt();
        System.out.println("main over");
    }
}

友情链接:Java线程阻塞中断和LockSupport的常见问题

你可能感兴趣的:(Java concurrent包源码走读(一))