Java中的ThreadLocal功能演示示例

 更新时间:2021年02月06日 17:10:14   作者:FunTester  
这篇文章主要介绍了Java中的ThreadLocal功能演示示例,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下

除了使用synchronized同步符号外,Java中的ThreadLocal是另一种实现线程安全的方法。在进行性能测试用例的编写过程中,比较简单的办法就是直接使用synchronized关键字,修饰对象、方法以及类。但是使用synchronized同步,这可能会影响应用程序的可伸缩性以及运行效率。但是如果要在多个线程之间共享对象又要保障线程安全,则除了synchronized之外没有特别适合测试的方法。

Java中的ThreadLocal是实现线程安全的另一种方法,它不满足同步要求,而是通过为每个线程提供Object的显式副本来消除共享。由于不再共享对象,因此不需要同步,它可以提高应用程序的可伸缩性和运行效率。

在本文中,会介绍有关ThreadLocal的基础知识点点,Demo中ThreadLocal的简单示例。

ThreadLocal简介

很多人几乎都没有用过ThreadLocal类,因为在测试中能用到的地方实在太少了,而且测试脚本的性能一般来讲都会很高,远超被测服务的处理能力,所以即使全部使用synchronized也不会有任何问题。

但是ThreadLocal有很多真正的使用场景,这就是为什么将其添加到标准Java平台库中的原因。尽管知道现在多线程编程测试中对于ThreadLocal应用并不多,但是我会在后期多进行一些实践,分享给各位。

以下是Java中ThreadLocal类的一些众所周知的用法:

  • ThreadLocal非常适合实现每个线程单例类或每个线程上下文信息(例如事务ID)。
  • 可以将任何非线程对象包装在ThreadLocal中,并且将其使用变为线程安全的。ThreadLocal的经典示例之一是共享SimpleDateFormat。由于SimpleDateFormat不是线程安全的,因此使用全局格式化程序可能无法正常工作,但是使用每个线程格式化程序当然可以工作。
  • ThreadLocal提供了另一种扩展Thread的方法。如果要保留信息或将信息从一个方法调用传递到另一个方法,则可以使用ThreadLocal进行传递。
  • 由于不需要修改任何方法,因此可以提供极大的灵活性。

没有两个线程可以看到彼此的ThreadLocal变量。J2EE应用程序服务器中有一个ThreadLocal的真实示例,该服务器使用Java ThreadLocal变量来跟踪事务和安全上下文。

为了避免过多的创建和共享全局实例时的切换成本,将诸如数据库连接之类的重对象作为ThreadLocal共享是很有意义的。

ThreadLocal演示Demo

package com.fun.ztest.java;

import com.fun.frame.SourceCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * ThreadLocal演示测试类
 */
public class FunTester extends SourceCode {

  public static Logger logger = LoggerFactory.getLogger(FunTester.class);

  /**
   * 这个是重点,通过ThreadLocal类重建线程私有的对象
   */
  private static final ThreadLocal<Object> format = new ThreadLocal() {

    @Override
    protected Object initialValue() {
      Object funTester = new Object();
      logger.info("初始化对象,线程: {} 对象: {}", Thread.currentThread().getName(), funTester.hashCode());
      return funTester;
    }
  };

  public static void main(String args[]) throws IOException, InterruptedException {
    for (int i = 0; i < 5; i++) {
      Thread t = new Thread(new Fun());
      t.start();
    }
  }

  /**
   * 获取对象
   *
   * @return
   */
  public static Object get() {
    return format.get();
  }


  static class Fun implements Runnable {

    @Override
    public void run() {
      logger.info("线程: {} 对象: {}", Thread.currentThread().getName(), FunTester.get().hashCode());
    }


  }


}


控制台输出

INFO-> 当前用户:fv,IP:10.60.193.37,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 初始化对象,线程: Thread-1 对象: 347384150
INFO-> 初始化对象,线程: Thread-2 对象: 142607688
INFO-> 线程: Thread-1 对象: 347384150
INFO-> 线程: Thread-2 对象: 142607688
INFO-> 初始化对象,线程: Thread-3 对象: 1008357237
INFO-> 初始化对象,线程: Thread-4 对象: 559951532
INFO-> 线程: Thread-3 对象: 1008357237
INFO-> 线程: Thread-4 对象: 559951532
INFO-> 初始化对象,线程: Thread-5 对象: 748958847
INFO-> 线程: Thread-5 对象: 748958847

Process finished with exit code 0

如果查看上述程序的输出,则会发现,当不同的线程调用ThreadLocal类的get()方法而不是调用其initialValue()方法时,该方法将为该线程创建Object的互斥实例对象。 由于Object在线程之间不共享,并且实质上在创建它自己的线程安全对象或者方法的线程本地是完全线程安全的。

ThreadLocal类知识点

  • Java的ThreadLocal在JDK 1.2上引入,但后来在JDK 1.4中进行了泛化,以在ThreadLocal变量上引入类型安全性。
  • ThreadLocal通常与Thread一起使用,由Thread执行的所有代码都可以访问ThreadLocal变量,但是两个线程看不到彼此的ThreadLocal变量。
  • 每个线程都拥有ThreadLocal变量的互斥副本,该副本在线程完成或死亡(正常情况下或由于任何异常)后才有进行垃圾回收,因为这些ThreadLocal变量没有任何其他线程引用。
  • Java中的ThreadLocal变量通常是类中的私有静态字段,并在Thread中维护其状态。

不要误解ThreadLocal是Synchronization的替代方法,它全部取决于你自己的程序设计。如果设计允许每个线程拥有自己的对象副本,则可以使用ThreadLocal。

项目中使用

这里一个处理requestid的类,通过ThreadLocal使用,可以保证每个请求都拥有唯一的一个追踪标记。

public class TraceKeyHolder {
  private static ThreadLocal<String> threadLocal = new ThreadLocal();

  public TraceKeyHolder() {
  }

  public static String getTraceKey() {
    return (String)threadLocal.get();
  }

  public static void setTraceKey(String traceKey) {
    threadLocal.set(traceKey);
  }

  public static void clear() {
    threadLocal.remove();
  }
}

以上就是Java中的ThreadLocal功能演示示例的详细内容,更多关于Java ThreadLocal功能的资料请关注脚本之家其它相关文章!

相关文章

  • 使用 Java 类 实现Http协议

    使用 Java 类 实现Http协议

    这篇文章主要介绍了用几个Java类简单的实现了Http协议相关资料,感兴趣的的朋友可以参考下面具体的文章内容
    2021-09-09
  • Java中Stream的flatMap与map使用场景及区别详解

    Java中Stream的flatMap与map使用场景及区别详解

    这篇文章主要介绍了Java中Stream的flatMap与map使用场景及区别详解,Stream 流式操作,一般用于操作集合即 List 一类的数据结构,简单来说 Stream 的 map 使得其中的元素转为另一种元素的映射(map)方法,需要的朋友可以参考下
    2024-01-01
  • Java获取电脑真实IP地址的示例代码

    Java获取电脑真实IP地址的示例代码

    这篇文章主要介绍了Java如何获取电脑真实IP地址,忽略虚拟机等IP地址的干扰,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-09-09
  • Java程序的初始化顺序,static{}静态代码块和实例语句块的使用方式

    Java程序的初始化顺序,static{}静态代码块和实例语句块的使用方式

    这篇文章主要介绍了Java程序的初始化顺序,static{}静态代码块和实例语句块的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Java设计模式之策略模式_动力节点Java学院整理

    Java设计模式之策略模式_动力节点Java学院整理

    策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。接下来通过本文给大家分享Java设计模式之策略模式,感兴趣的朋友一起看看吧
    2017-08-08
  • java中synchronized关键字的3种写法实例

    java中synchronized关键字的3种写法实例

    synchronized是Java中的关键字,是一种同步锁,下面这篇文章主要给大家介绍了关于java中synchronized关键字的3种写法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • IntelliJ IDEA创建maven多模块项目(图文教程)

    IntelliJ IDEA创建maven多模块项目(图文教程)

    这篇文章主要介绍了IntelliJ IDEA创建maven多模块项目(图文教程),非常具有实用价值,需要的朋友可以参考下
    2017-09-09
  • java实现解析二进制文件的方法(字符串、图片)

    java实现解析二进制文件的方法(字符串、图片)

    本篇文章主要介绍了java实现解析二进制文件的方法(字符串、图片),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 详解Mybatis核心配置文件

    详解Mybatis核心配置文件

    今天给大家带来的是关于Java的相关知识,文章围绕着Mybatis核心配置文件展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Netty启动流程服务端channel初始化源码分析

    Netty启动流程服务端channel初始化源码分析

    这篇文章主要为大家介绍了Netty启动流程服务端channel初始化源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03

最新评论