StopWatch与ThreadLocal

news2024/10/6 10:36:51

目录

1、StopWatch

1、1作用:

1、2方法:

1、3使用方法

 2、ThreadLocal

2、1什么是ThreadLocal

2、2简单例子

2、3使用ThreadLocal带来的四个好处

2、4主要方法

2、5ThreadLocal内存泄漏问题


1、StopWatch

1、1作用:

 统计代码块耗时时间

1、2方法:

  • 构造器:可以使用无参数构造器,也可使用传入一个String类型的id,创建一个指定了id的StopWatch
  • start():可以不传入参数,开始一个无名称的任务的计时,也可以传入String类型的参数来开始指定任务名的任务计时
  • stop():停止当前任务的计时
  • isRunning():返回此stopWatch是否正在计时某任务
  • getTotalTimeMillis():返回所有任务的总体执行时间(毫秒单位)
  • getLastTaskTimeMillis():返回上一个任务的耗时(毫秒单位)
  • prettyPrint():优美地打印所有任务的详细耗时情况

1、3使用方法

引入依赖,Spring框架自带,可不引入

<!-- spring核心包 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${spring.version}</version>
</dependency>
public class StopWatchTest {
    // 用于模拟一些操作
    private static void doSomeThing() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("任务一");
        doSomeThing();
        stopWatch.stop();

        stopWatch.start("任务二");
        doSomeThing();
        stopWatch.stop();
        System.out.println("stopWatch.isRunning() = " + stopWatch.isRunning());
        System.out.println(stopWatch.prettyPrint());
        System.out.println("stopWatch.getTotalTimeMillis() = " + stopWatch.getTotalTimeMillis());
        System.out.println("stopWatch.getLastTaskTimeMillis() = " + stopWatch.getLastTaskTimeMillis());
    }

}

 2、ThreadLocal

2、1什么是ThreadLocal

ThreadLocal 叫做本地线程变量,ThreadLocal 中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal 为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量.

同一个ThreadLocal所包含的对象,在不同的Threa中有不同的副本,这里有几点需要注意:

  • 因为每个Thread内有自己的实例副本,且该副本只能由当前Thread使用,这也是ThreadLocal命名的由来。
  • 既然每个Thread都有自己的实例副本,且其他Thread不可访问,那就不存在多线程共享的问题

ThreadLocal提供了线程本地的实例,它与普通变量的区别在于:

  • 每个使用该变量的线程都会初始化一个完全独立的实例副本。
  • ThreadLocal变量通常被private static修饰。
  • 当一个线程结束时,它所使用的所有ThreadLocal相对的实例副本都可被回收。

ThreadLocal适用于每个线程需要自己独立的实例,且该实例需要在多个方法中被使用。即变量在线程间隔离,但是在方法和类间共享。

每个Thread对象都有一个ThreadLocalMap,每个ThreadLocalMap可以存储多个ThreadLocal

2、2简单例子

如果没有ThreadLocal,定义一个全局变量后,所有线程都更改的是同一个值

public class TestThread1 {
    //线程本地存储变量


    public static int n =0;
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {//启动三个线程
            Thread t = new Thread() {
                @Override
                public void run() {
                    add10ByThreadLocal();
                }
            };
            t.start();
        }
    }

    /**
     * 线程本地存储变量加 5
     */
    private static void add10ByThreadLocal() {
        for (int i = 0; i < 5; i++) {

            n += 1;
            System.out.println(Thread.currentThread().getName() + " n=" + n);
        }
    }
}

最终 值为15,还可能出现线程安全问题

package com.ljx.splearn;

public class TestThreadLocal {
	
	//线程本地存储变量
	private static final ThreadLocal<Integer> THREAD_LOCAL_NUM = new ThreadLocal<Integer>() {
		@Override
		protected Integer initialValue() {
			return 0;
		}
	};
 
	public static void main(String[] args) {
		for (int i = 0; i < 3; i++) {//启动三个线程
			Thread t = new Thread() {
				@Override
				public void run() {
					add10ByThreadLocal();
				}
			};
			t.start();
		}
	}
	
	/**
	 * 线程本地存储变量加 5
	 */
	private static void add10ByThreadLocal() {
		for (int i = 0; i < 5; i++) {
			Integer n = THREAD_LOCAL_NUM.get();
			n += 1;
			THREAD_LOCAL_NUM.set(n);
			System.out.println(Thread.currentThread().getName() + " : ThreadLocal num=" + n);
		}
	}
	
}

 

打印结果:启动了 3 个线程,每个线程最后都打印到 "ThreadLocal num=5",而不是 num 一直在累加直到值等于 15

经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。

还有比如一个请求中需要访问三个服务,三个服务需要在子线程中依次修改用户信息,通常从session中取到用户信息,然后给三个线程操作,这样会出现线程安全问题,需要用锁来保证

使用ThreadLocal后,每个线程都是独立的,互不影响

2、3使用ThreadLocal带来的四个好处

  • 不需要加锁,提高执行效率
  • 线程安全
  • 更高效地利用内存节省开销,上面例子中,相比于成千上万个任务,每个任务都新建一个SimpleDateFormat,显然用ThreadLocal可以节省内存和开销。
  • 免去传参的繁琐,不需要每次都传同样的参数,ThreadLocal使得代码耦合度更低,更优雅

2、4主要方法

  • initialValue()方法会返回当前线程对应的初始值,这是一个延迟加载的方法,只有在调用get()方法的时候才会触发。
  • 如果不重写initialValue()方法,这个方法会返回null,一般使用匿名内部类的方法重写initialValue()方法,以便在后续的使用中可以初始化副本对象。
  • 当线程第一次调用get()方法访问变量的时候,会调用initialValue()方法,除非线程先前调用了set()方法,在这种情况下,不会为线程调用本initialValue()
  • 通常,每个线程最多调用一次initialValue()方法,但如果已经调用一次remove()方法后,再调用get()方法,则可以再次调用initialValue(),相当于第一次调用get()

ThreadLocalMap 类是每个线程Thread类里面的变量,但ThreadLocalMap这个静态内部类定义在ThreadLocal类中

2、5ThreadLocal内存泄漏问题

ThreadLocalMap中的每个Entry都是一个对key弱引用,同时,每个 Entry 都包含了一个对value的强引用

正常情况下,当线程终止时,保存在ThreadLocalMap中的value也会被垃圾回收,因为没有任何强引用了,但是在项目中我们一般使用线程池,线程都是复用的,一般线程都不会结束,那么key对应的value就不会被回收

使用结束后及时调用remove()方法,删除对应的Entry对象,可以避免内存泄漏,所以使用完ThreadLocal之后,应该调用remove()方法。

可同步参考 ThreadLocal详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/819943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前端|CSS系列第4篇】面试官:你了解居中布局吗?

欢迎来到前端CSS系列的第4篇教程&#xff01;如果你正在寻找一种简单而又强大的前端技术&#xff0c;以使你的网页和应用程序看起来更加专业和美观&#xff0c;那么居中布局绝对是你不能错过的重要知识。 在前端开发中&#xff0c;实现居中布局是一项必备技能&#xff0c;无论…

DC电源模块输出电压的调节范围

BOSHIDA DC电源模块输出电压的调节范围 DC电源模块是一种可以将交流电转换为直流电的设备&#xff0c;可以广泛应用于电子、通信、工业自动化等领域。在实际使用中&#xff0c;输出电压的调节范围非常重要&#xff0c;因为它决定了该模块能够适应的电器设备的种类和使用范围。…

(自控原理)自动控制的一般概念

1、自动控制理论发展简史 1.1经典控制理论&#xff08;19世纪初—20世纪50年代) 时域法 复域法(根轨迹法) 频域法 1.2 现代控制理论&#xff08;20世纪60年代—&#xff09; 线性系统 自适应控制预测控制 最优控制 鲁棒控制 滑模控制 最佳估计 容错控制 大系统复杂系统 系…

golang自带的命令行解析库flag库实践

1. 简介 flag用于解析命令行选项。有过类 Unix 系统使用经验的童鞋对命令行选项应该不陌生。例如命令ls -al列出当前目录下所有文件和目录的详细信息&#xff0c;其中-al就是命令行选项。 命令行选项在实际开发中很常用&#xff0c;特别是在写工具的时候。 指定配置文件的路径…

高压开关柜温度在线监测系统设计

摘要&#xff1a;在当前的社会之中&#xff0c;电力资源是最重要的能源资源之一&#xff0c;人们对于电力资源的依赖程度也逐渐升高&#xff0c;到目前为止&#xff0c;任何人的生活与工作都不能离开电力资源&#xff0c;这就导致电力系统的普及型大大提高。电力系统具有着极高…

小程序原生实现左右锚点联动

效果 wxml <view classbox><scroll-view scroll-y scroll-with-animation style"width:25%"><view classnav><view wx:for"{{navList}}" wx:keyindex class"title {{index active ?select:}}"data-index{{index}} bin…

el-select 中加了filterable 点击箭头下拉框回收不去问题

解决方式①&#xff1a;参考连接&#xff1a;&#xff08;亲测有用&#xff09;【element-select】添加过滤属性以及change后下拉框异常_element select过滤时,不收起下拉框_Y.哈哈的博客-CSDN博客 1、添加过滤属性后点击下箭头不收起下拉框 2、change通过dialog触发事件后&…

新能源光学膜厚测量仪

能源是人类社会可持续发展的动力源泉和重要生存基础。近年来&#xff0c;新能源的研究受到世界各国的高度重视&#xff0c;包括太阳能、风能和潮汐能等在内的可再生能源正在成为传统化石燃料有希望的替代品&#xff0c;因此&#xff0c;开发低成本、大规模的能源转换技术与新型…

【laravel+vue2 】医院信息化手术麻醉临床信息管理系统源码

近年来&#xff0c;医院信息化成为医院领域的推广重点&#xff0c;HIS、LIS、PACS、EMR等信息系统的相继出现&#xff0c;显著提高了医院业务的运行效率。手术麻醉系统作为医院信息系统的一部分&#xff0c;由监护设备数据采集系统和麻醉信息管理系统两个子系统组成。 一、医院…

【LeetCode】【数据结构】单链表OJ常见题型(一)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 目录 前言&#xff1a; 【LeetCode】203.移除链表元素 【LeetCo…

不同语言操作符的优先级

看到标题&#xff0c;可能会心生疑惑: 这么基础且重要的操作&#xff0c;不同语言不应该是一致的吗&#xff1f; 并不一定&#xff0c;比如对于右移运算和加法运算&#xff0c;Go就与其他多数语言表现得不一致&#xff1a; Go: package mainimport "fmt"func main() …

解密Redis:应对面试中的缓存相关问题

文章目录 1. 缓存穿透问题及解决方案2. 缓存击穿问题及解决方案3. 缓存雪崩问题及解决方案4. Redis的数据持久化5. Redis的过期删除策略和数据淘汰策略6. Redis分布式锁和主从同步7. Redis集群方案8. Redis的数据一致性保障和高可用性方案 导语&#xff1a; 在面试过程中&#…

社区说|Flutter 一知半解,带你拨云见月

Hello&#xff0c;大家好&#xff0c;我是 Flutter GDE 郭树煜&#xff0c;今天的主题是科普向的分享内容&#xff0c;主要是带大家更全面的去理解 Flutter &#xff0c;尽可能帮助大家破除一些误解&#xff0c;分享内容不会特别长&#xff0c;但是应该会帮助你从新认识下 Flut…

C++源码使用make生成动态库和静态库

我这个新电脑&#xff0c;没装Homebrew&#xff0c;把这个复制进终端安装。 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 下载过程如下所示

blender凹凸感和置换形变

一、怎么做出凹凸感 需要三个部分的内容&#xff1a; 1、一个基础的纹理&#xff1a;告诉计算机需要用一个什么样的纹理做凹凸&#xff0c;纹理一般采用黑白&#xff0c;在计算机里面&#xff0c;从 0 - 1之间的值可以用从黑到白之间不同的灰度来表示因此&#xff0c;有一张黑白…

char类型到底是有符号还是无符号的?

最近在整理代码时&#xff0c;发现有一些如下类型的警告&#xff1a; ..\XXXXX\XXXXX.c(224): warning: #186-D: pointless comparison of unsigned integer with zero 这个警告的意思是无符号数与0比较是无意义&#xff0c;而我报警告的代码行如下&#xff1a; char len_v…

阿里用户序列建模ETA

End-to-End User Behavior Retrieval in Click-Through Rate Prediction Model 摘要 现实很少有工作可以处理长序列用户建模的问题&#xff0c;SIM提出了两阶段方法。第一阶段&#xff0c;辅助任务旨在从长序列用户行为检索最相关的用户行为序列。第二阶段&#xff0c;经典的…

位图和 DC 有什么特别之处?

相信设备上下文 (DC, Device Context) 对你来说&#xff0c;应该很熟悉。 基本工作方式是&#xff0c;你可以通过调用 SelectObject 来将画笔(Pen)&#xff0c;画刷(Brush)&#xff0c;字体(Font)和位图(Bitmap)等这些对象选入设备上下文中&#xff0c;但是&#xff0c;这里的位…

Android 面试题 应用程序结构 十一

&#x1f525; Framework主要包含以下模块 &#x1f525; ActivityManagerService 这是一个Activity的管理者&#xff0c;负责管理所有Activity的生命周期。WindowManagerService 它是手机屏幕的的管理者&#xff0c;管理着屏幕的详细情况&#xff0c;所有对屏幕的操作最终都…

ChatGPT学python——制作自己的AI模型(一)初步了解

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…