一位工作5年的小伙伴在面试的时候被问到这样的问题。Java中保证线程安全的方法有哪些?今天,我就把我的理解分享给大家。一、线程不安全的原因在回答这个问题之前,首先要了解对象线程不安全的原因。主要有以下三个原因:原子性:CPU执行过程中一个或多个操作被打断。可见性:线程对象的共享变量的修改导致另一个线程不能立即看到它。有序性:程序执行的顺序不遵循代码执行的顺序。原子性和可见性比较好理解,重点分析顺序。为什么程序执行的顺序和代码写的顺序不一致?这就需要了解Java平台的两个编译器,静态编译器javac和动态编译器jit(正好赶上)。静态编译器将.java文件编译成.class文件,JVM加载后即可执行。动态编译器就是将.class文件编译成机器码,然后交由JVM执行。有时,动态编译器会为了程序的整体性能对指令进行重新排序,但这会导致源代码中指定的内存访问顺序与实际执行顺序不一致,就会出现线程不安全的问题。2、如何保证线程安全那么,对于以上三种情况,如何保证对象的线程安全呢?第一个是原子性。(1)JDK提供了很多Atomic类,比如AtomicInteger、AtomicLong、AtomicBoolean等。这些类通过CAS保证是原子的。(2)另外,Java还提供了多种锁机制,保证锁中的代码块在同一时刻只能被一个线程执行。比如使用synchronized来加锁。这样就可以保证当一个线程读写资源时,其他线程不能对该资源进行操作,从而保证线程安全。第二个是为了能见度。也可以通过使用synchronized关键字加锁来解决。同时Java提供了volatile关键字。比synchronized性能好,也能保证修改对其他线程可见。volatile一般用于对变量的写操作,在不依赖于当前值的场景下,比如状态标记等。第三个是为了秩序。也可以使用synchronized关键字来定义一个同步代码块,或者一个synchronized方法来保证有序性。另外,也可以通过Lock接口来保证顺序。以上就是Java中保证线程安全的思路。当然,有很多方法可以保证对象的线程安全。比如你也可以使用ThreadLocal来实现多线程之间的数据隔离,使用final关键字等,这里就不一一列举了。最后留一个思考问题,单独使用volatile关键字能保证线程安全吗?
