多线程进阶之路——如何保证线程的安全

82 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情


开始学习多线程相关知识,大体看了一下,知识点还是挺多的,坚持学习,道阻且长。

线程安全问题

在多线程编程中,一个不可避免的也是最需要关注的问题就是线程安全。与进程拥有独立的进程空间不一样,一个进程内的多个线程是共享该进程的资源的。由于CPU通常为多核架构,且线程又是并发执行的,所以可能会出现同一时刻存在多个线程同时访问同一个资源的现象。

为了解决以上线程对共享资源的并发操作而导致的数据不一致性问题,在JDK层面即可解决并发访问、修改的问题,从而实现线程安全。

synchronized 关键字

Java 提供了 synchronized 关键字来实现互斥锁,保证多个线程对共享资源的互斥访问。

synchronized 关键字可以用在方法或代码块中。

  • 类的静态方法(对当前类加锁)
  • 类的成员方法(对当前对象实例加锁)
  • 代码块(对指定的对象或类加锁)
public class SynchronizedDemo {
    public static synchronized void testStaticMethod() {

    }

    public synchronized void testMemberMethod() {

    }

    private Object monitor = new Object();
    public void testCodeBlock() {
        synchronized (monitor) {
        }
    }
}

volatile 关键字

volatile 关键字修饰变量,用来实现共享变量的线程可见性,还可以防止指令的重排。但是无法保证操作的原子性。

synchronized 和 volatile 的区别?

synchronized 关键字和 volatile 关键字是两个互补的存在,而不是对立的存在

  • volatile 关键字是线程同步的轻量级实现,所以 volatile 性能肯定比 synchronized 关键字要好 。但是 volatile 关键字只能用于变量而 synchronized 关键字修饰方法以及代码块 。
  • volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。
  • volatile关键字主要用于解决变量在多个线程之间的可见性,而synchronized 关键字解决的是多个线程之间访问资源的同步性。

final 关键字

如果多个线程只是对共享资源进行读操作,则不会存在线程安全问题,可以使用 final 关键字修饰,使用 final 修饰某个对象后,该对象是只读、不可变的,不需要额外的加锁操作,性能更高。

ThreadLocal 线程本地变量

空间换时间,通过使用 ThreadLocal 对共享变量进行包装,使得每个线程都包含这个共享变量的一个副本,实现了共享变量对每个线程的独立性,不需要通过加锁实现线程安全。

在使用 ThreadLocal 时,需要衡量该共享变量的内存占用问题,一般是整数等简单的数据类型使用。


因为是零基础学习多线程,很多地方会理解的不到位,作为一个新人,如有错误之处,还请指出^^