Java并发理论基础

时间:2020-07-01 09:40:43   收藏:0   阅读:66

Java并发理论基础

为什么需要多线程

并发出现问题的原因

可见性

可见性:一个线程对共享变量的修改,另外一个线程可以立即看到.

示例:

int i = 0;

// 线程1
i = 10;

// 线程2
j = i;

// 若执行顺序是:线程2先执行,线程1再执行,则j=0
// 若线程1先执行,线程2再执行,则j=10
// 执行赋值语句时: 先从内存读取当前值到高速缓存中,修改后,再将数值写入到内存中.

原子性

原子性:一个操作或多个操作要么全部执行并且执行过程不被打断,要么都不执行.

示例:转账问题:A给B转账.A的余额减少,B的余额增加.两个动作必须都成功或都失败.

有序性

有序性:程序执行的顺序按照代码的先后顺序执行.

指令重排序(instruction reorder):程序中的代码顺序与实际执行的顺序并不一定是一致的.

三种类型的重排序:

流程:
源代码 ==> 编译器优化重排序 ==> 指令级并行重排序 ==> 内存系统重排序 ==> 最终执行的指令序列

JMM(Java内存模型)

Happens-Before规则

  1. 单一线程原则(Single Thread Rule): 一个线程内,靠前的操作先于靠后的操作完成.
  2. 管程锁定规则(Monitor Lock Rule): unlock操作先于同一个锁的lock操作.
  3. volatile变量规则(Volatile Variable Rule): 对一个volatile变量的写操作先于读操作.
  4. 线程启动规则(Thread Start Rule): start()方法调用先于此线程的所有动作.
  5. 线程加入规则(Thread Join Rule): 一个线程调用另外一个线程的join()方法,则该线程在另外线程执行结束后再继续执行.
  6. 线程中断规则(Thread Interruption Rule): 对线程调用interrupt()方法先于被中断的线程检测到中断事件的发生.
  7. 对象终结规则(Finalizer Rule): 一个对象的初始化咸鱼发生finalize()方法前.
  8. 传递性(Transitivity): 操作A先于操作B,操作B先于操作C,则操作A先于操作C.

线程安全的程度

分类:

不可变

示例:

// 使用Collections.unmodifiableList()获得一个不可变的集合
ArrayList<Integer> list = new ArrayList<>();
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
unmodifiableList.add(1);

/* 底层直接将add改写成抛出异常
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
*/

绝对线程安全

任何时刻都不需要额外的同步措施.

相对线程安全

示例:

// ConcurrentHashMap是线程安全类,但是多个指令顺序执行时,
// 不能保证同一线程的不同指令连续执行而不被其他线程打断
ConcurrentHashMap chm = new ConcurrentHashMap<Integer,Integer>();

@Test
public void test() throws InterruptedException {
    Thread t1 = new Thread(()->{
        for (int i = 0; i < 10; i++) {
            chm.put(i,i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    Thread t2 = new Thread(()->{
        for (int i = 0; i < 10; i++) {
            chm.put(i,i+1);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    t1.start();
    t2.start();
    TimeUnit.SECONDS.sleep(2);
    Iterator iterator = chm.entrySet().iterator();
    while (iterator.hasNext())
        System.out.println(iterator.next());
}

线程兼容

对象本身不是线程安全的,但通过适当的同步手段保证并发执行时正确的执行.

对象对立

无论采取何种同步措施,都无法在多线程下并发使用.

线程安全的实现

  1. 互斥同步: synchronizedReentrantLock.
  2. 非阻塞同步: CAS, AtomicInteger和ABA问题.
  3. 无同步方案: 栈封闭, 线程本地存储(Thread Local Storage), 可重入代码(Reentrant Code).

基于冲突检测的乐观并发策略:

无同步方案:

ThreadLocal

参考:

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!