利用ThreadLocal解决线程同步问题

2020-04-03 16:10:52 浏览数 (1)

线程安全是Java性能测试中绕不过去的一个坎,想要其测试必需对其有所了解,所谓知己知彼百战不殆。之前我也写过一些性能测试中线程安全和线程同步的文章:

  • 服务端性能优化之双重检查锁
  • Java并发BUG基础篇
  • Java并发BUG提升篇
  • 如何在匿名thread子类中保证线程安全
  • Java服务端两个常见的并发错误
  • 线程安全类在性能测试中应用

但是就运行效能而言,加锁同步又会带来更多的性能消耗,有些得不偿失。在某些并发场景下加锁同步并不是唯一解决线程安全的方法,还有两种,其中一种是基于CAS的替代方案,我已经之前文章线程安全类在性能测试中应用中使用的就是这个方案,包括性能测试框架第三版中也多次使用到这个方案,有兴趣的同学可以再看一看这两篇文章。

下面将另外一个避免同步的方案:避免同步发生的一个方法就是在每个线程中使用不同的对象,这样访问对象时就不存在竞争了。为保证线程安全,很多Java对象是同步的,但是它们未必需要共享。另一方面,很多Java对象创建的成本很高,或者是会占用大量内存。java.lang.ThreadLocal这个方法就可以很好解决这个问题。每次有一个线程访问这个对象,就会得到一个新的对象,避免了线程竞争同一个对象,也就用不到同步,可以很大程度提升性能。

下面是Demo:

代码语言:javascript复制

package com.fun;

import com.fun.frame.SourceCode;

public class AR extends SourceCode {

    static ThreadLocal<String> local = new ThreadLocal<String>() {
        public String initialValue() {
            String s = new String(getNanoMark()   EMPTY);
            output(s.hashCode());
            return s;
        }
    };

    public static void main(String[] args) throws InterruptedException {
        AR ar = new AR();
        ar.ss();
        ar.ss();
        Thread thread = new Thread(() -> ar.ss());
        Thread thread2 = new Thread(() -> ar.ss());
        thread.start();
        thread2.start();
        thread.join();
        thread2.join();
    }

    public void ss() {
        local.get();
    }
    
}

控制台打印如下:

代码语言:javascript复制
INFO-> 当前用户:fv,IP:192.168.0.104,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.3
INFO-> 851397249
INFO-> 1851572413
INFO-> 1875674350

Process finished with exit code 0


  • 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。

0 人点赞