JUC并发相关

1. 并发终结之线程安全

2020-09-18  本文已影响0人  涣涣虚心0215

多个线程共享进程的资源,比如内存地址。
同一进程中的线程访问相同的变量,并从同一个堆中分配对象,实现了良好的数据共享。但是如果没有明确的同步来管理共享数据,会导致线程安全问题。
无状态的对象肯定是线程安全的,那么对于有可变状态的对象,只要有多于一个线程访问给定的状态变量,而且其中一个线程会写入该变量,此时必须使用同步来协调线程对改变量的访问。可以用synchronized提供独占锁,也可以使用volatileLock或者原子变量
举个栗子:

public class Test {
    private int count;
    public synchronized void addCount() {
        System.out.println(Thread.currentThread().getName() + " " + ++this.count);
    }
    public synchronized void minusCount() {
        System.out.println(Thread.currentThread().getName() + " " + --this.count);
    }
    public static void main(String[] args) {
        Test test = new Test();
        Thread t1 = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                test.addCount();
            }
        }, "ThreadAdd");

        Thread t2 = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                test.minusCount();
            }
        }, "ThreadMinus");
        t1.start();
        t2.start();
    }
}
没有synchronized的输出结果:
ThreadAdd 1
ThreadMinus -1
ThreadAdd 0
ThreadMinus -1
ThreadAdd 0
ThreadMinus -2
加了synchronized的输出结果:
ThreadAdd 1
ThreadMinus 0
ThreadMinus -1
ThreadAdd 0
ThreadAdd 1
ThreadMinus 0

在这个栗子里,两个线程对于count这个可变状态的修改,是属于竞态条件的。
最常见的竞态条件是:check-then-act(比如new Object())以及 read-modify-save(比如count++)这样的复合操作。为了保证线程安全性,这种复合操作必须是原子的

那么总结一下如何做到线程安全呢?

  1. 无状态:没有任何成员变量的类。
  2. 让类不可变:让状态不可变
    |-- 对于一个类,所有的成员变量应该都是私有的,而且所有的成员变量都应该加上final关键字。
    |-- 根本就不提供可修改成员变量的地方,同时成员变量也不作为方法的返回值。
  3. 加锁:保证操作的原子性,加锁同样保证内存可见性。
  4. volatile和CAS:保证类的可见性,最适合一个线程写,多个线程读的情形,且只适合一个变量的原子操作。
  5. 栈封闭:定义方法的局部变量。
  6. 安全的发布:不能让别的线程有机会拿到并修改本线程内部数据的机会,要么get()返回一个线程安全的容器,要么返回对象的副本,深拷贝的副本。
  7. ThreadLocal:让共享状态变成线程私有。
上一篇 下一篇

猜你喜欢

热点阅读