自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

不規(guī)范使用ThreadLocal導(dǎo)致的bug,說多了都是淚

開發(fā) 前端
我們?cè)趯憳I(yè)務(wù)代碼時(shí),正確的理解線程的全生命周期以及執(zhí)行原理,對(duì)我們提升代碼的健壯性其實(shí)很有幫助。

ThreadLocal一般用于線程間的數(shù)據(jù)隔離,通過將數(shù)據(jù)緩存在ThreadLocal中,可以極大的提升性能。但是,如果錯(cuò)誤的使用Threadlocal,可能會(huì)引起不可預(yù)期的bug,以及造成內(nèi)存泄露。

因?yàn)榫€程重用導(dǎo)致的信息錯(cuò)亂的bug

有時(shí)我們會(huì)在一個(gè)接口中緩存某些數(shù)據(jù)到ThreadLocal中,但是我們要意識(shí)到,處理請(qǐng)求的這些線程是由tomcat提供的,而tomcat提供的線程都是配置在一個(gè)線程池中的。

也就是說,線程是可能被重用的,如果線程一旦被重用,而ThreadLocal的數(shù)據(jù)沒有及時(shí)重置,就會(huì)導(dǎo)致數(shù)據(jù)被混亂使用。

以下方的接口為例,先獲取當(dāng)前線程中保存的數(shù)據(jù)信息,將參數(shù)中的name保存到ThreadLocal中以后,再獲取一次。

@GetMapping(value = "/threadLocal")
public ResponseEntity<Object> threadLocal(String name) {
String before = Thread.currentThread().getName() + ":" + threadLocal.get();
//先獲取值,理論上應(yīng)該是null
System.out.println("before:" + before);
threadLocal.set(name);
String after = Thread.currentThread().getName() + ":" + threadLocal.get();
//設(shè)置完參數(shù)值再獲取一次
System.out.println("after:" + after);
return ResponseEntity.ok().build();
}

為了盡快復(fù)現(xiàn)線程重用導(dǎo)致的問題,我們將
servlet.tomcat.threads.max設(shè)置為1,這樣每次請(qǐng)求使用的都是同一個(gè)線程。

第一次請(qǐng)求接口,數(shù)據(jù)看起來很正常:

但是第二次請(qǐng)求接口時(shí),可以看到線程仍然是http-nio-8080-exec-1,但是before卻打印出了第一次請(qǐng)求的參數(shù)test。

這就是因?yàn)闆]有及時(shí)重置ThreadLocal導(dǎo)致的數(shù)據(jù)錯(cuò)誤。

正確使用的姿勢(shì)

修正的辦法就是處理完接口之后要及時(shí)清理ThreadLocal。

@GetMapping(value = "/threadLocal")
public ResponseEntity<Object> threadLocal(String name) {
try {
String before = Thread.currentThread().getName() + ":" + threadLocal.get();
//先獲取值,理論上應(yīng)該是null
System.out.println("before:" + before);
threadLocal.set(name);
String after = Thread.currentThread().getName() + ":" + threadLocal.get();
//設(shè)置完參數(shù)值再獲取一次
System.out.println("after:" + after);
} finally {
//清理數(shù)據(jù)
threadLocal.remove();
}
return ResponseEntity.ok().build();
}

更優(yōu)雅的處理方式

可能也有的朋友會(huì)說,每次都要使用try finally處理線程數(shù)據(jù),未免也太麻煩了。其實(shí),我們可以使用攔截器或者過濾器自動(dòng)幫我們完成數(shù)據(jù)的初始化以及清理工作。

最后

我們?cè)趯憳I(yè)務(wù)代碼時(shí),正確的理解線程的全生命周期以及執(zhí)行原理,對(duì)我們提升代碼的健壯性其實(shí)很有幫助。有時(shí)我們覺得底層原理很枯燥乏味,開發(fā)業(yè)務(wù)就是寫增刪改查,多線程用的也很少,但我們只是沒有意識(shí)到,我們的代碼一直跑在tomcat提供的線程池中,本身就是一個(gè)多線程的環(huán)境。

除了tomcat的線程池,我們自定義的線程池其實(shí)也會(huì)有這個(gè)問題,大家可以看看自己的業(yè)務(wù)代碼是否踩過這個(gè)坑。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2018-04-11 15:42:04

開源項(xiàng)目姿勢(shì)

2014-10-13 09:43:15

程序員

2021-09-11 19:00:54

Intro元素MemoryCache

2021-08-10 09:58:59

ThreadLocal內(nèi)存泄漏

2021-09-27 10:15:10

故障業(yè)務(wù)方電腦

2022-03-17 08:55:43

本地線程變量共享全局變量

2015-09-09 08:45:49

JavaThreadLocal

2021-05-06 08:55:24

ThreadLocal多線程多線程并發(fā)安全

2024-03-26 09:29:27

MySQLDDL

2016-01-05 17:59:32

VR英偉達(dá)

2009-03-09 14:22:12

ApacheJavaEEJCP

2012-09-18 09:17:34

Java規(guī)范代碼代碼

2024-06-11 00:04:00

對(duì)象AdvisorAdvice

2023-11-29 14:20:16

iOS 17Bug蘋果

2020-09-18 15:08:13

5G網(wǎng)絡(luò)技術(shù)

2017-10-20 14:23:01

動(dòng)態(tài)數(shù)據(jù)大數(shù)據(jù)數(shù)據(jù)采集

2024-10-28 08:15:32

2013-04-18 09:55:05

程序員

2009-01-04 17:08:41

2019-01-31 01:31:28

華為
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)