- 浏览: 372890 次
文章分类
最新评论
-
strchi:
这个网站,什么都没有了
做小说搜索网站,这个是不是有可能会侵权的呢? -
从此醉:
楼主倒是给出解决办法啊
Java虚拟机支持的最大内存限制 -
kjmmlzq19851226:
又要增强客户体验,又要降低伪造攻击的概率,╮(╯▽╰)╭,程序 ...
Web安全测试之跨站请求伪造(CSRF)篇(图) -
zhangxinze:
linux下使用Java获取客户端ip地址?大家有何高见,我现 ...
怎样用Java来获取真实的IP地址 -
k_kid9157:
学习 感谢分享:-)
log4j的ConversionPattern参数的格式含义
ThreadLocal与synchronized
Java良好的支持多线程。使用java,我们可以很轻松的编程一个多线程程序。但是使用多线程可能会引起并发访问的问题。synchronized和ThreadLocal都是用来解决多线程并发访问的问题。大家可能对synchronized较为熟悉,而对ThreadLocal就要陌生得多了。
并发问题。当一个对象被两个线程同时访问时,可能有一个线程会得到不可预期的结果。
一个简单的java类Studnet
- public class Student {
- private int age=0;
- public int getAge() {
- return this.age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
public class Student { private int age=0; public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
一个多线程类ThreadDemo.
这个类有一个Student的私有变量,在run方法中,它随机产生一个整数。然后设置到student变量中,从student中读取设置后的值。然后睡眠5秒钟,最后再次读student的age值。
- public class ThreadDemo implements Runnable{
- Student student = new Student();
- public static void main(String[] agrs) {
- ThreadDemo td = new ThreadDemo();
- Thread t1 = new Thread(td,"a");
- Thread t2 = new Thread(td,"b");
- t1.start();
- t2.start();
- }
- /* (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- public void run() {
- accessStudent();
- }
- public void accessStudent() {
- String currentThreadName = Thread.currentThread().getName();
- System.out.println(currentThreadName+" is running!");
- // System.out.println("first read age is:"+this.student.getAge());
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- this.student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge());
- }
- }
public class ThreadDemo implements Runnable{ Student student = new Student(); public static void main(String[] agrs) { ThreadDemo td = new ThreadDemo(); Thread t1 = new Thread(td,"a"); Thread t2 = new Thread(td,"b"); t1.start(); t2.start(); } /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { accessStudent(); } public void accessStudent() { String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); // System.out.println("first read age is:"+this.student.getAge()); Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge()); } }
运行这个程序,屏幕输出如下:
a is running!
b is running!
thread b set age to:33
thread b first read age is:33
thread a set age to:81
thread a first read age is:81
thread b second read age is:81
thread a second read age is:81
需要注意的是,线程a在同一个方法中,第一次读取student的age值与第二次读取值不一致。这就是出现了并发问题。
synchronized
上面的例子,我们模似了一个并发问题。Java提供了同步机制来解决并发问题。synchonzied关键字可以用来同步变量,方法,甚至同步一个代码块。
使用了同步后,一个线程正在访问同步对象时,另外一个线程必须等待。
Synchronized同步方法
现在我们可以对accessStudent方法实施同步。
public synchronized void accessStudent()
再次运行程序,屏幕输出如下:
a is running!
thread a set age to:49
thread a first read age is:49
thread a second read age is:49
b is running!
thread b set age to:17
thread b first read age is:17
thread b second read age is:17
加上了同步后,线程b必须等待线程a执行完毕后,线程b才开始执行。
对方法进行同步的代价是非常昂贵的。特别是当被同步的方法执行一个冗长的操作。这个方法执行会花费很长的时间,对这样的方法进行同步可能会使系统性能成数量级的下降。
Synchronized同步块
在accessStudent方法中,我们真实需要保护的是student变量,所以我们可以进行一个更细粒度的加锁。我们仅仅对student相关的代码块进行同步。
- synchronized(this) {
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- this.student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
synchronized(this) { Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } }
运行方法后,屏幕输出:
a is running!
thread a set age to:18
thread a first read age is:18
b is running!
thread a second read age is:18
thread b set age to:62
thread b first read age is:62
thread b second read age is:62
需要特别注意这个输出结果。
这个执行过程比上面的方法同步要快得多了。
只有对student进行访问的代码是同步的,而其它与部份代码却是异步的了。而student的值并没有被错误的修改。如果是在一个真实的系统中,accessStudent方法的操作又比较耗时的情况下。使用同步的速度几乎与没有同步一样快。
使用同步锁
稍微把上面的例子改一下,在ThreadDemo中有一个私有变量count,。
private int count=0;
在accessStudent()中, 线程每访问一次,count都自加一次, 用来记数线程访问的次数。
- try {
- this.count++;
- Thread.sleep(5000);
- }catch(InterruptedException ex) {
- ex.printStackTrace();
- }
try { this.count++; Thread.sleep(5000); }catch(InterruptedException ex) { ex.printStackTrace(); }
为了模拟线程,所以让它每次自加后都睡眠5秒。
accessStuden()方法的完整代码如下:
- String currentThreadName = Thread.currentThread().getName();
- System.out.println(currentThreadName+" is running!");
- try {
- this.count++;
- Thread.sleep(5000);
- }catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- System.out.println("thread "+currentThreadName+" read count:"+this.count);
- synchronized(this) {
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- this.student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge());
String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); try { this.count++; Thread.sleep(5000); }catch(InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread "+currentThreadName+" read count:"+this.count); synchronized(this) { Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } } System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge());
运行程序后,屏幕输出:
a is running!
b is running!
thread a read count:2
thread a set age to:49
thread a first read age is:49
thread b read count:2
thread a second read age is:49
thread b set age to:7
thread b first read age is:7
thread b second read age is:7
我们仍然对student对象以synchronized(this)操作进行同步。
我们需要在两个线程中共享count失败。
所以仍然需要对count的访问进行同步操作。
- synchronized(this) {
- try {
- this.count++;
- Thread.sleep(5000);
- }catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- System.out.println("thread "+currentThreadName+" read count:"+this.count);
- synchronized(this) {
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- this.student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge());
- long endTime = System.currentTimeMillis();
- long spendTime = endTime - startTime;
- System.out.println("花费时间:"+spendTime +"毫秒");
synchronized(this) { try { this.count++; Thread.sleep(5000); }catch(InterruptedException ex) { ex.printStackTrace(); } } System.out.println("thread "+currentThreadName+" read count:"+this.count); synchronized(this) { Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } } System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge()); long endTime = System.currentTimeMillis(); long spendTime = endTime - startTime; System.out.println("花费时间:"+spendTime +"毫秒");
程序运行后,屏幕输出
a is running!
b is running!
thread a read count:1
thread a set age to:97
thread a first read age is:97
thread a second read age is:97
花费时间:10015毫秒
thread b read count:2
thread b set age to:47
thread b first read age is:47
thread b second read age is:47
花费时间:20124毫秒
我们在同一个方法中,多次使用synchronized(this)进行加锁。有可能会导致太多额外的等待。
应该使用不同的对象锁进行同步。
设置两个锁对象,分别用于student和count的访问加锁。
- private Object studentLock = new Object();
- private Object countLock = new Object();
- accessStudent()方法如下:
- long startTime = System.currentTimeMillis();
- String currentThreadName = Thread.currentThread().getName();
- System.out.println(currentThreadName+" is running!");
- // System.out.println("first read age is:"+this.student.getAge());
- synchronized(countLock) {
- try {
- this.count++;
- Thread.sleep(5000);
- }catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- System.out.println("thread "+currentThreadName+" read count:"+this.count);
- synchronized(studentLock) {
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- this.student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- }
- System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge());
- long endTime = System.currentTimeMillis();
- long spendTime = endTime - startTime;
- System.out.println("花费时间:"+spendTime +"毫秒");
private Object studentLock = new Object(); private Object countLock = new Object(); accessStudent()方法如下: long startTime = System.currentTimeMillis(); String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); // System.out.println("first read age is:"+this.student.getAge()); synchronized(countLock) { try { this.count++; Thread.sleep(5000); }catch(InterruptedException ex) { ex.printStackTrace(); } } System.out.println("thread "+currentThreadName+" read count:"+this.count); synchronized(studentLock) { Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); this.student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+this.student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } } System.out.println("thread "+currentThreadName +" second read age is:"+this.student.getAge()); long endTime = System.currentTimeMillis(); long spendTime = endTime - startTime; System.out.println("花费时间:"+spendTime +"毫秒");
这样对count和student加上了两把不同的锁。
运行程序后,屏幕输出:
a is running!
b is running!
thread a read count:1
thread a set age to:48
thread a first read age is:48
thread a second read age is:48
花费时间:10016毫秒
thread b read count:2
thread b set age to:68
thread b first read age is:68
thread b second read age is:68
花费时间:20046毫秒
与两次使用synchronized(this)相比,使用不同的对象锁,在性能上可以得到更大的提升。
由此可见synchronized是实现java的同步机制。同步机制是为了实现同步多线程对相同资源的并发访问控制。保证多线程之间的通信。
可见,同步的主要目的是保证多线程间的数据共享。同步会带来巨大的性能开销,所以同步操作应该是细粒度的。如果同步使用得当,带来的性能开销是微不足道的。使用同步真正的风险是复杂性和可能破坏资源安全,而不是性能。
ThreadLocal
由上面可以知道,使用同步是非常复杂的。并且同步会带来性能的降低。Java提供了另外的一种方式,通过ThreadLocal可以很容易的编写多线程程序。从字面上理解,很容易会把ThreadLocal误解为一个线程的本地变量。其它ThreadLocal并不是代表当前线程,ThreadLocal其实是采用哈希表的方式来为每个线程都提供一个变量的副本。从而保证各个线程间数据安全。每个线程的数据不会被另外线程访问和破坏。
我们把第一个例子用ThreadLocal来实现,但是我们需要些许改变。
Student并不是一个私有变量了,而是需要封装在一个ThreadLocal对象中去。调用ThreadLocal的set方法,ThreadLocal会为每一个线程都保持一份Student变量的副本。所以对student的读取操作都是通过ThreadLocal来进行的。
- protected Student getStudent() {
- Student student = (Student)studentLocal.get();
- if(student == null) {
- student = new Student();
- studentLocal.set(student);
- }
- return student;
- }
- protected void setStudent(Student student) {
- studentLocal.set(student);
- }
protected Student getStudent() { Student student = (Student)studentLocal.get(); if(student == null) { student = new Student(); studentLocal.set(student); } return student; } protected void setStudent(Student student) { studentLocal.set(student); }
accessStudent()方法需要做一些改变。通过调用getStudent()方法来获得当前线程的Student变量,如果当前线程不存在一个Student变量,getStudent方法会创建一个新的Student变量,并设置在当前线程中。
Student student = getStudent();
student.setAge(age);
accessStudent()方法中无需要任何同步代码。
完整的代码清单如下:
TreadLocalDemo.java
- public class TreadLocalDemo implements Runnable {
- private final static ThreadLocal studentLocal = new ThreadLocal();
- public static void main(String[] agrs) {
- TreadLocalDemo td = new TreadLocalDemo();
- Thread t1 = new Thread(td,"a");
- Thread t2 = new Thread(td,"b");
- t1.start();
- t2.start();
- }
- /* (non-Javadoc)
- * @see java.lang.Runnable#run()
- */
- public void run() {
- accessStudent();
- }
- public void accessStudent() {
- String currentThreadName = Thread.currentThread().getName();
- System.out.println(currentThreadName+" is running!");
- Random random = new Random();
- int age = random.nextInt(100);
- System.out.println("thread "+currentThreadName +" set age to:"+age);
- Student student = getStudent();
- student.setAge(age);
- System.out.println("thread "+currentThreadName+" first read age is:"+student.getAge());
- try {
- Thread.sleep(5000);
- }
- catch(InterruptedException ex) {
- ex.printStackTrace();
- }
- System.out.println("thread "+currentThreadName +" second read age is:"+student.getAge());
- }
- protected Student getStudent() {
- Student student = (Student)studentLocal.get();
- if(student == null) {
- student = new Student();
- studentLocal.set(student);
- }
- return student;
- }
- protected void setStudent(Student student) {
- studentLocal.set(student);
- }
- }
public class TreadLocalDemo implements Runnable { private final static ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] agrs) { TreadLocalDemo td = new TreadLocalDemo(); Thread t1 = new Thread(td,"a"); Thread t2 = new Thread(td,"b"); t1.start(); t2.start(); } /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { accessStudent(); } public void accessStudent() { String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName+" is running!"); Random random = new Random(); int age = random.nextInt(100); System.out.println("thread "+currentThreadName +" set age to:"+age); Student student = getStudent(); student.setAge(age); System.out.println("thread "+currentThreadName+" first read age is:"+student.getAge()); try { Thread.sleep(5000); } catch(InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread "+currentThreadName +" second read age is:"+student.getAge()); } protected Student getStudent() { Student student = (Student)studentLocal.get(); if(student == null) { student = new Student(); studentLocal.set(student); } return student; } protected void setStudent(Student student) { studentLocal.set(student); } }
运行程序后,屏幕输出:
b is running!
thread b set age to:0
thread b first read age is:0
a is running!
thread a set age to:17
thread a first read age is:17
thread b second read age is:0
thread a second read age is:17
可见,使用ThreadLocal后,我们不需要任何同步代码,却能够保证我们线程间数据的安全。
而且,ThreadLocal的使用也非常的简单。
我们仅仅需要使用它提供的两个方法
void set(Object obj) 设置当前线程的变量的副本的值。
Object get() 返回当前线程的变量副本
另外ThreadLocal还有一个protected的initialValue()方法。返回变量副本在当前线程的初始值。默认为null
ThreadLocal是怎么做到为每个线程都维护一个变量的副本的呢?
我们可以猜测到ThreadLocal的一个简单实现
- public class ThreadLocal
- {
- private Map values = Collections.synchronizedMap(new HashMap());
- public Object get()
- {
- Thread curThread = Thread.currentThread();
- Object o = values.get(curThread);
- if (o == null && !values.containsKey(curThread))
- {
- o = initialValue();
- values.put(curThread, o);
- }
- return o;
- }
- public void set(Object newValue)
- {
- values.put(Thread.currentThread(), newValue);
- }
- public Object initialValue()
- {
- return null;
- }
- }
public class ThreadLocal { private Map values = Collections.synchronizedMap(new HashMap()); public Object get() { Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)) { o = initialValue(); values.put(curThread, o); } return o; } public void set(Object newValue) { values.put(Thread.currentThread(), newValue); } public Object initialValue() { return null; } }
由此可见,ThreadLocal通过一个Map来为每个线程都持有一个变量副本。这个map以当前线程为key。与synchronized相比,ThreadLocal是以空间换时间的策略来实现多线程程序。
Synchronized还是ThreadLocal?
ThreadLocal以空间换取时间,提供了一种非常简便的多线程实现方式。因为多个线程并发访问无需进行等待,所以使用ThreadLocal会获得更大的性能。虽然使用ThreadLocal会带来更多的内存开销,但这点开销是微不足道的。因为保存在ThreadLocal中的对象,通常都是比较小的对象。另外使用ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
发表评论
-
java资源获取分析
2009-11-27 14:41 2334在开发java程序的过程中,我们经常要做的一件事就是获取资源。 ... -
java字符集笔记
2009-05-25 19:05 1170概述 本文主要包括以 ... -
log4j的ConversionPattern参数的格式含义
2009-03-20 15:50 3164Log4j建议只使用四个级别,优先级从高到低分别是ERROR、 ... -
Apache HTTP Server 与 Tomcat 的三种连接方式介绍
2009-03-20 12:00 1244整合 Apache Http Server 和 Tomcat ... -
JavaScript不能做到的6,7事
2009-02-22 11:19 1219虽然在很多方面,JavaScr ... -
TreeMap的使用及注意事项
2008-10-30 20:58 2541TreeMap是红黑树算法 ... -
如何注意HttpSession的线程
2008-09-13 15:12 1409HttpSession session = req ... -
ThreadLocal相关知识
2008-09-03 14:53 1611首先,ThreadLocal 不是用来解决共享对象的多线程访问 ... -
JAXP的介绍
2008-08-29 10:37 3823摘要: JAXP (全称Java API for XML P ... -
简单的运用Lucene进行检索
2008-06-17 20:20 1184Lucene不是一个完整的全文索引应用,而是是一个用Java ... -
(转)Java虚拟机参数详解
2008-06-17 11:18 1802http://www.5a520.cn 小说520网 下面的讨 ... -
JAVA面试题(4)
2008-05-31 18:36 1309数据库方面: 1. 存储过 ... -
J2EE初学者需要理解的问题
2008-05-31 18:35 1099一、J2EE提出的背景 1、 ... -
JAVA面试题(3)
2008-05-31 18:32 4993一、Java基础知识1.Java有那些基本数据类型,Strin ... -
java面试题(续)
2008-05-29 21:15 11764. 多线程:在同一应用程序中,有多个顺序流同时执行。同步和异 ... -
java面试题
2008-05-29 21:13 1970应聘Java笔试时可能出现 ...
相关推荐
ThreadLocal 相关知识点 ThreadLocal 是 Java 语言中的一种机制,用于提供线程内部的局部变量。在多线程环境下,ThreadLocal 变量可以保证各个线程的变量相对独立于其他线程内的变量。这种机制可以帮助开发者在多...
2. 并发编程:ThreadLocal是解决并发问题的一种策略,它提供了一种避免共享状态的方式,减少了锁的使用。 3. 内存管理:了解Java的内存模型和垃圾回收机制,才能理解ThreadLocal的内存泄漏风险和弱引用的作用。 4. ...
**线程局部变量(ThreadLocal)** 在Java编程中,`ThreadLocal`是...以上就是关于`ThreadLocal`及其内部类`ThreadLocalMap`的基础知识,它们在多线程编程中起到关键作用,帮助开发者实现高效、安全的线程局部变量管理。
2. **数据存储**:在没有全局状态或者不希望使用同步机制的情况下,ThreadLocal 可以用来在各个线程间存储局部状态。 3. **生命周期**:ThreadLocal 变量仅在其创建线程内有效,当线程结束时,其存储的值也就被释放...
java高并发相关知识,threadLocal,分布式锁,java各种锁等
"ThreadLocal相关知识点总结" ThreadLocal是Java中的一种机制,用于在多线程环境中保存线程上下文信息,并且提供了一种解决多线程程序并发问题的思路。下面是对ThreadLocal的主要知识点的总结: 1. ThreadLocal的...
在"ThreadLocal测试工程"中,我们可以探索以下几个关键知识点: 1. **ThreadLocal类的使用**:ThreadLocal提供了一个`set(T value)`方法用于设置当前线程的ThreadLocal变量值,`get()`方法用于获取当前线程的变量值...
2. 尽量减少ThreadLocal变量的使用数量。过多的ThreadLocal变量会造成不必要的内存消耗和哈希碰撞。 3. 在使用完ThreadLocal后,及时清理。例如,在finally块中进行清理操作,或者使用try-with-resources语句。 ###...
2. **ThreadLocal详解**: ThreadLocal是Java提供的一种线程局部变量,每个线程都拥有自己独立的ThreadLocal副本,互不影响。在上述代码中,创建了一个ThreadLocal实例,然后在线程的run()方法中设置值,每个线程...
2. **SessionFactory的创建**:SessionFactory是Hibernate的核心,它是线程安全的,负责管理数据库的连接和Session的创建。一般在应用启动时创建一次。 3. **ThreadLocal的使用**:在`HibernateUtil`中,可能有一个...
ThreadLocal 提供了一种线程隔离的变量存储方式,而 Java 中的四种引用类型则帮助我们更好地控制对象的生命周期和内存管理,理解这些概念对于理解和使用 ThreadLocal 至关重要,同时也是面试中经常考察的知识点。
《InheritableThreadLocal & ...总之,理解并熟练运用ThreadLocal和InheritableThreadLocal是Java并发编程中不可或缺的知识点,它们提供了线程安全的局部变量管理机制,能够帮助开发者构建更健壮的多线程应用。
2 InheritableThreadLocal 的局限性:InheritableThreadLocal 仅限于父线程给子线程来传递数据,不能解决跨线程池之间的数据传递问题。 3 TransmittableThreadLocal 的实现原理:TransmittableThreadLocal 是基于...
知识点2:ThreadLocal数据丢失 ThreadLocal是Java中的一种线程局部存储机制,用于在线程中传递数据。但是,在Hystrix线程隔离模式下,ThreadLocal数据可能会丢失,因为Hystrix将请求放入Hystrix的线程池中去执行,...
以下是对标题和描述中所述知识点的详细说明: 1. **与 Synchronized 的区别** - `synchronized` 关键字是用于控制对共享资源的并发访问,它确保同一时刻只有一个线程可以执行特定代码块,从而实现线程同步。而 `...
"ThreadLocal知识点详解" ThreadLocal是一个本地线程副本变量工具类,主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个...
这个Entry数组的键是ThreadLocal对象本身(弱引用),而值是线程相关的对象。这样设计的原因是,一个线程可能有多个ThreadLocal实例,每个实例对应不同的变量副本。 ThreadLocal的`set`方法是将值与当前线程关联的...
### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...
总结一下,ThreadLocal的主要知识点包括: 1. **线程隔离**:每个线程拥有ThreadLocal变量的独立副本,互不影响。 2. **共享对象,独立值**:所有线程共享同一个ThreadLocal对象,但访问时看到的是各自的副本。 3. ...