Java线程安全经验分享

目录

使用volatile关键字

使用线程安全的数据结构

使用ThreadLocal

加锁

阻塞锁 & 非阻塞锁

synchronized method

synchronized block

公平锁 & 非公平锁

可重入锁 & 不可重入锁

分布式锁

双检锁


使用volatile关键字

    public volatile int a = 88;
    public static volatile int b = 99;

对于某个field 如果只有一个线程读写 其它线程只是读,使用volatile能保证 其它线程读这个field时读出来的值是最新的,不使用则不能保证;

对于某个field 如果有多个线程读写,则不能使用volatile。

使用线程安全的数据结构

  • AtomicInteger:i++ 不是线程安全的(这里的i为int类型),atomicInteger.getAndIncrement()等 是线程安全的;

  • CopyOnWriteArrayList

  • ConcurrentHashMap

  • ……

使用ThreadLocal

private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

... ...

threadLocal.set()
threadLocal.get()

 

加锁

阻塞锁 & 非阻塞锁

阻塞锁:死等,获取到锁才往下走。

非阻塞锁:获取不到锁的话,返回说没获取到锁。。

synchronized method

        public synchronized void someMethod() {
          
        }

        public static synchronized void someMethod() {
          
        }

instance synchronized method用this进行加锁,static synchronized method用currentClazz进行加锁,能实现线程安全。

Question:这样有什么问题呢?

适合一个对象/类里只有一个方法需要加锁时用。

 

synchronized block

那上面的问题如何解决呢?可以使用synchronized block。

        synchronized (lockObject) {
						code block
        }

我们先来复现一下上面的问题:

比如说某个类里有两个方法A和B,其中各有一个synchronizedBlock A 和 B,它们的锁都是 "this" for instance method 或者是 "currentClazz" for static method,然后有100个线程,那么某个线程在执行方法A时,其它99个线程就不能执行方法B。

Question:如何解决这个问题呢?

lockObject的选择:期望加锁的话,lockObject各个线程看起来得是一样的。

公平锁 & 非公平锁

  • 公平锁:讲究先来后到,先来的先得锁
  • 非公平锁:抢锁,谁抢到锁算谁的

可重入锁 & 不可重入锁

可重入就是说某个线程已经获得了某个锁,可以再次获取这个锁而不会出现死锁,e.g.

 

  • synchronized是可重入的,加锁和解锁自动进行,不必担心最后是否释放锁;
  • ReentrantLock是可重入的,加锁和解锁手动进行,且次数需要一样,否则其他线程无法获得锁;
  • ReentrantLock相对于synchronized有个很大的优势是 可以实现公平锁(new ReentrantLock(true))。

分布式锁

针对多台机器的情况,需要在多台机器都能看到的一个公共的地方来实现锁,常见的有基于数据库的、基于缓存的、基于zk的等。

Question:finally段一定会执行吗?

分布式锁需要给锁加一个生命周期。

推荐使用tair的expireLock/expireUnlock。

双检锁

尽量避免加锁导致的并发降低:

public class Singleton {
  
    private static Singleton uniqueSingleton;

    private Singleton() {}

    public Singleton getInstance() {
        if (null == uniqueSingleton) {
            synchronized (Singleton.class) {
                if (null == uniqueSingleton) {
                    uniqueSingleton = new Singleton();
                }
            }
        }
        return uniqueSingleton;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值