【个人总结】提高线程安全的常用方法与涉及层面

线程安全

在编写多线程程序时常常遇到竞争问题,也就是说多个线程同时尝试去访问某个地址,修改某个变量,这就很容易发生错误和难以想象的结果。
例如对一个变量,一个线程尝试a = a - 1然后a = a + 1。理论上并不会改变a的值,但是在执行第二步的时候a可能已经被别的线程修改过了,最后产生了错误的结果。
所以对于多线程程序,如果保证线程安全是很重要的。尤其是对于服务器,如果不注意线程安全以及应对高并发,很容易产生错误。

使用线程安全的Collection

Java中很多Collection都有线程安全的封装类。例如HashMap,可以用ConcurrentHashMap来代替,再比如一个List,可以Collection.synchronizedList进行包装,从而提高其安全性。还有很多例子,这里不一一列举。

synchronized

Java中提高线程安全最常用的方法便是“上锁”,也就是给代码添加synchronized。

public synchronized void method() {
//... ...
}

而上锁本身又存在类、对象、方法等层面。简单的说,即类的同步、某个对象的同步、某个方法的同步。
如果在方法的签名处加synchronized,相当于将这个方法的全部的代码体用synchronized(this)包住,也就是对于这个对象的访问是同步的,如果其他方法涉及到synchronized(this),需要等待这个方法执行完毕。这样便实现了对象层面的同步,这个类中加锁的方法无法同时进行。

synchronized(obj) {
//... ...
}

当然,也可以包住某个代码段,这样虽然可能存在因为设置位置不当造成的风险,但是更加灵活,更有利于提高性能。显然,如果在所有的方法都加了锁,多线程程序就变成了单线程程序,性能肯定会受到影响。
如果想要在类的层面加锁,也就是对于这个类的所有对象访问都不能并发,那么可以使用静态变量,因为其对于所有实例都是一样的,而不像普通的成员变量,每个对象都有自己的。
例如:

    /**
     * Locker for thread safe.
     */
    private static final Object LOCKER = new Object();

将其作为obj便可以实现类层面的锁。

总结

线程安全是程序正确性的重要保证,多线程程序一定要在这里多加考虑,否则会引起难以预测的问题。而提高线程安全便是要清楚什么地方可能会发生竞争,并在相应的位置从具体的层面进行“上锁”,保证其安全性。

发布了75 篇原创文章 · 获赞 28 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Swocky/article/details/92774554