欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

系列:多线程(二)线程安全

程序员文章站 2022-03-26 20:25:36
多线程:线程安全原子三大特性原子性可见性有序性模拟不安全问题原子性一个对象Count count,10个线程执行+1 100次,输出最后结果(正确:1000)demo@Dataclass Count { private int count; public void add() { ++count; }}void test2() throws InterruptedException { ThreadPoolExecutor poo...

系列:多线程(二)线程安全

原子三大特性

原子性

可见性

有序性

模拟不安全问题

原子性

一个对象Count count,10个线程执行+1 100次,输出最后结果(正确:1000)

demo
@Data
class Count {
    private int count;

    public void add() {
        ++count;
    }
}

void test2() throws InterruptedException {
    ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
    Count count = new Count();
    for (int i = 0; i < 10; ++i) {
        pool.submit(() -> {
            for (int j = 0; j < 100; ++j) {
                count.add();
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    pool.shutdown();
    TimeUnit.SECONDS.sleep(3);
    System.out.println(count.getCount());
}
输出

789、813…

解决

synchronized、Lock、原子类…

public synchronized void add() {
    ++count;
}
public synchronized int getCount() {
    return count;
}

可见性

demo
@Setter
class Task extends Thread {
    private  boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

    @Override
    public void run() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        flag = true;
        System.out.println(Thread.currentThread().getName() + " flag = " + flag);
    }
}

public class VolatileTest {
    public static void main(String[] args) throws InterruptedException {
        Task task = new Task();

        task.start();
        while (true) {
            if (task.isFlag()) {
                System.out.println("终止了");
                break;
            }
        }
    }
}
输出

Thread-0 flag = true

// 主线程没有输出,一直while循环,检测,但是由于flag非volatile,task线程即使修改了flag = true,主线程仍获取不到其值变化

提示:如果主线程在while循环内,加上sleep,就可以检测到flag的变化

解决

private volatile boolean falg = false;

有序性(略)

线程安全

不可变必然安全

  1. 线程间不共享

    • 不共享
  2. 线程间共享

    • ThreadLocal:线程创建共享变量的副本

    • 线程同步

原理

CPU

参考:https://juejin.im/post/5c6b99e66fb9a049d51a1094

JMM内存操作

lock和unlock

read和load

use和assign

store和write

happens-before原则

1)程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。
2)锁定规则:一个unLock操作先行发生于后面对同一个锁的Lock()操作。
3)volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。
4)传递规则:如果操作A先行发生与操作B,而操作B先行发生于操作C,则操作A先行发生于操作C。
5)线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
6)线程终端规则:对线程interrupt()方法的调用先行发生与被中断线程的代码检测到中断事件的发生(只有执行了interrupt()方法才可以检测到中断事件的发生)。
7)线程终结规则:线程中所有操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束,Thread.isAlive()的返回值手段检测到线程已经终止执行。
8)对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始。

内存屏障:禁止重排序

内存屏障前和后的不能乱序,即内存屏障前不能重排序到屏障后,内存屏障后不能重排序到屏障前。

内存屏障:volatile变量读写前后加指令

对象的布局

对象头 + 类型指针 + 实力数据 + 对齐

图源自:https://www.bilibili.com/video/BV1xK4y1C7aT?p=3

系列:多线程(二)线程安全

volatile

作用:线程可见性;防止指令重排序

  1. Java: volatile int i

  2. class: ACC_VOLATILE

  3. JVM的内存屏障

    屏障两端不可以重排

  4. Hotspot实现:lock指令

JSR内存屏障:

LoadLoad
StoreStore
LoadStore
StoreLoad

volatile写

StoreStore
volatile 写
StoreLoad

volatile读

LoadLoad
volatile 读
LoadStore

synchronized

作用:同步

锁升级:无锁 --> 偏向锁 --> 轻量级锁 --> 重量级锁

字节码:

语句块:monitorenter和monitorexit

方法:flags加ACC_SYNCHRONIZED(执行方法前先获取monitor,执行完后释放monitor)

monitor

任何一个对象都有一个monitor与之关联,当一个monitor被持有后,对象将处于锁定状态。

synchronized对象被锁,MarkWord的锁标识位为10(重量级锁),其指针指向monitor对象的起始地址。

锁优化

自适应CAS自旋

锁消除

锁粗化

偏向锁,轻量级锁

偏向锁和轻量级锁
偏向锁:ThreadID的CAS
轻量级锁:MarkWord的lock word的CAS更新为当前线程Lock Record的指针,并将Lock Record的owner指针指向锁对象MarkWord
	线程栈帧:Lock Record,锁记录,当前锁对象的MarkWord拷贝
重量级锁

涉及底层OS,存在用户态到核心态的切换。

参考

https://juejin.im/post/5c6b99e66fb9a049d51a1094#heading-24

https://blog.csdn.net/u011877584/article/details/81157317

https://www.bilibili.com/video/BV1xK4y1C7aT?p=6

https://juejin.im/post/5b4eec7df265da0fa00a118f

本文地址:https://blog.csdn.net/qq_31854267/article/details/107677607

相关标签: Java