线程安全!线程安全!!线程安全!!!
鼠鼠我最近被线程安全这个词弄得好烦啊,那既然如此就来写一篇常见的线程安全类防止以后鼠鼠我的大脑又宕机了忘记了.......
这里我们讨论的线程安全的是指,多个线程调用它们同一个实例的某个方法时,是线程安全的。他们的每个方法是原子的,但是他们多个方法的组合并不是原子的。举个例子如下:
Hashtable hs = new Hashtable();
if (Objects.isNull(hs.get("key"))){
hs.put("key","value");
}
Hashtable的每个方法都是现成安全的,但是组合在一起的时候仍然会有线程上下文切换的风险导致的非线程安全。
String类,Integer类
这里把这两个类放在一起说,因为他们都是不可变类,因为其内部的状态是没法改变的,因此它们的方法都是线程安全的,话不多说直接上源码。
这里用String举例,首先String是一个有final修饰的字符数组,为了防止子类去破坏父类中方法的行为,final修饰的是不允许被修改的,然后鼠鼠这里用subString() 方法进行举例,可以看到最后一行是new了一个新的String对象,我们跟进后发现在构造方法中存在一个范围复制。因此每次对字符串类进行更改的时候底层都是new了一个新的对象,从而不会出现线程安全问题。
Integer类在这里不过多赘述,读者可以跟着源码进行阅读。
StringBuffer类
可以看到StringBuffer首先也是被final关键字修饰的类,StringBuffer的方法中使用了synchronized 关键字进行同步处理,当一个线程想要去访问StringBuffer对象的方法时,其他线程必须等待这个线程执行完后才能继续访问,这样就保证了在多线程环境下,对 StringBuffer 的操作不会发生冲突,从而确保了线程安全性。
Random类
Random
类在 Java 中是线程安全的。这是因为 Random
类的实现使用了一个 AtomicLong
类型的变量来维护其种子状态,并且在生成随机数时使用了 CAS(Compare-And-Swap)操作,这使得在多线程环境下,不同线程之间的状态变更能够被正确同步,从而确保了线程安全性。
在 Random
类的实现中,每个线程都会有一个独立的种子状态,因此即使多个线程同时使用 Random
对象生成随机数,它们之间也不会产生竞争或者冲突,从而保证了线程安全性。
总的来说,Random
类的线程安全性是由其实现机制所保证的,而不需要开发者在使用时额外考虑线程安全的问题。
Vector类,Hashtable类
在Vector类和Hashtable类中的方法大多是由synchronized关键字修饰的,但是这个类和下述的Hashtable类已经被弃用。
java.util.concurrent包下的类
我们平日说的JUC就是这几个字母的缩写,这里简述为什么java.util.concurrent包下的类是线程安全的。
-
使用了同步机制:这些类通常使用了各种同步机制,如锁、信号量、原子变量等,来确保多个线程可以安全地访问共享资源。
-
提供了高级并发工具:java.util.concurrent包提供了许多高级的并发工具,如线程池、并发集合、并发队列等,这些工具在设计时考虑了线程安全性。
-
避免了常见的并发问题:这些类避免了一些常见的并发问题,如死锁、竞态条件等,通过设计和实现来确保线程安全。
-
经过严格测试和优化:Java并发包下的类经过了严格的测试和优化,以确保其在多线程环境下的正确性和性能。
java.util.concurrent包下的类的效率已经不断地在优化,在日常使用中推荐使用java.util.concurrent包下的类来代替可以出现的线程安全类。