java保证线程安全的方式有哪些?
同时,针对不同的应用场景,还可以使用分布式锁来实现线程安全,比较常用的分布式锁实现方式有,基于数据库实现的分布式锁(不常用,除非是单数据库,但是不便于后期扩展),基于redis实现的分布式锁、基于zookeeper实现的分布式锁。让这些变量在多线程环境下访问(get/set)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal采⽤了“以空间换时间”的⽅式,为每⼀个线程都提供⼀
导致线程不安全的原因有,主要有三个:
1.原子性:一个或者多个操作在CPU执行过程中被中断
2.可见性:一个线程共享变量的修改,导致另一个线程不能立即看到
3.有序性:程序执行的顺序没有按照代码的先后顺序执行
java平台编译器:静态编译器javac(加载后直接执行),动态编译器jit(.class文件再编译成机器码,可能会对指令进行重排序,指定的内存访问顺序跟源代码编写不一致)。
针对原子性,
1.JDK提供的Atomic类,通过CAS来保证原子性。比如AtomicInteger、AtomicLong、AtomicBoolean等。
2.java提供了各种锁机制,比如synchronized关键字。
针对可见性,
1.使用synchronized关键字加锁来解决
2.java提供volatile关键字,比synchronized关键字性能更优
针对有序性,
1.使用synchronized关键字定义同步代码块或同步方法
2.通过lock接口来保证有序性
同时,针对不同的应用场景,还可以使用分布式锁来实现线程安全,比较常用的分布式锁实现方式有,基于数据库实现的分布式锁(不常用,除非是单数据库,但是不便于后期扩展),基于redis实现的分布式锁、基于zookeeper实现的分布式锁。还有一种就是使用ThreadLocal来进行线程隔离。ThreadLocal类是作为线程内部的局部变量而提供的。让这些变量在多线程环境下访问(get/set)时能保证各个线程里的变量相对独立于其他线程内的变量。通过ThreadLocal创建的变量只能被当前线程访问,对其他线程不可见,故别的线程无法访问和修改,也就是说:对线程公有化变成对线程私有化。事实上每个线程中都有一个ThreadLocal变量副本。
相比于锁的性能:
java在使用锁的使用中会导致运行效率降低,ThreadLocal的使用彻底避免对共享资源的竞争,同时又可以不影响效率。ThreadLocal采⽤了“以空间换时间”的⽅式,为每⼀个线程都提供⼀份变量的副本,从⽽实现同时访问⽽互不影响,但因为每个线程都维护着⼀份副本,对内存空间的占⽤会增加。
更多推荐
所有评论(0)