并发编程笔记之线程安全

119 阅读3分钟

在并发编程系列中,有很多的概念,也涉及到相当多的技术点,而线程安全却是并发编程中的最基础的原则之一。

众所周知,每个独立的应用程序都运行在各自的进程之中。进程之间相互分离、各自独立执行。当需要资源时,需要由操作系统来统一分配。随着多核处理器的发展,多线程的概念深入人心。恰当的使用线程,可以降低开发和维护的开销,并提升系统的性能。

在并发编程之中,并不会涉及到过多的线程和锁,但是要想保证并发编程的安全性以及数据的一致性,正确的使用线程和锁是非常必要的。而线程安全的本质就是对共享、可变的对象的状态进行安全的访问。共享指的是一个对象以及它的可访问的属性可以被多个线程访问到;而可变指的是,这些访问到这个对象的线程可以修改相应的对象。而线程安全要做的就是,要保证一个对象在共享、可用的状态下依然保证数据的一致性。

在《Java并发编程实践》一书中,说道:“一个类是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为。”

在什么情况下,一个类是线程安全的呢?

1、“无状态”的类:所谓的无状态,指的就是一个没有属性的对象。当一个对象中没有公共属性的时候,任何可以访问到该类的线程都无法对共享状态做出改变。这种方式看似猥琐,却极其实用。因此,我们可以说,“无状态”的类永远是线程安全的类。

2、使用原子引用的单状态类:原子引用来自于大名鼎鼎的java.util.concurrent(也就是所谓的JUC)包,在这个包中的一个子包----atmoic,这个包里面有很多原子变量类:

1628246505.jpg

当我们在一个类中,使用了相应的类时,可以保证我们的类是线程安全的。

3、锁:首先就是Java内置的synchronized关键字,说起这个关键字,它在刚出现的时候,由于它的重量级别被不少人为之诟病。以至于,发展到最后,很多人都对这个关键字望而却步。而它在Java 1.8之中,迎来了一次特别重大的优化,就是这次优化。使得这个关键字得到越来越的人的青睐。

一个synchronized包含两个部分:第一个就是锁对象,如果是这个关键字锁住的是一个成员方法,那么这个锁对象就是所在的类的对象;而如果这个关键字修饰的是静态方法,那么这个锁对象就是当前的class对象,也就是所谓的全局锁。要注意,Java内置的锁都是互斥锁,所谓互斥锁就是一个线程获取了锁对象,其他想要获取该锁对象的线程就需要等到这个锁被释放之后,才能获取。而如果是一个线程想要获取自己锁住的对象,是可以获取到的,这个特性就叫做可重入特性。

在实际使用过程中,这个关键字需要慎用。因为,它会强制性的保证把我们被锁住的代码以串行的方式执行来保证线程安全。因此,我们需要使得锁住的代码尽可能的短,以达到线程安全和并发执行的平衡状态。