-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Affected files: docs/03编程语言/Java/01Java基础/Java语法:switch.md docs/03编程语言/Java/01Java基础/Q:Collectors.toMap有null值处理.md docs/03编程语言/Java/01Java基础/Q:Integer类型如何比较大小?.md docs/03编程语言/Java/01Java基础/Q:Java如何实现深拷贝对象?.md docs/03编程语言/Java/01Java基础/Q:RPC接口返回时,为什么建议使用包装类?.md docs/03编程语言/Java/01Java基础/Q:protected的控制范围.md docs/03编程语言/Java/01Java基础/Q:try块中多个catch,所有都检查吗?.md docs/03编程语言/Java/01Java基础/Q:反射为什么比较慢?.md docs/03编程语言/Java/01Java基础/Q:反射的常见应用有哪些?.md docs/03编程语言/Java/01Java基础/Q:反序列化时序列化id不一样会怎样?.md docs/03编程语言/Java/01Java基础/Q:如何对比小数(浮点数)的大小?.md docs/03编程语言/Java/01Java基础/Q:序列化对某个字段加密或解密?.md docs/03编程语言/Java/01Java基础/Q:接口、抽象类、实现类最佳实践.md docs/03编程语言/Java/01Java基础/Q:正则中如何多次匹配字符串中的模式子串?.md docs/03编程语言/Java/01Java基础/assets/Q:序列化对某个字段加密或解密?/userAccount.ser.jpg docs/03编程语言/Java/02JVM/JVM内存结构.md docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构1.png docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构1.webp docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构2.png docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构2.webp docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构3.png docs/03编程语言/Java/02JVM/assets/JVM内存结构/jvm内存结构3.webp docs/03编程语言/Java/02JVM/assets/双亲委派模型/双亲委派模型.png docs/03编程语言/Java/02JVM/assets/双亲委派模型/类加载器.png docs/03编程语言/Java/02JVM/assets/垃圾回收算法/标记-整理(压缩)算法.png docs/03编程语言/Java/02JVM/assets/垃圾回收算法/标记-整理(压缩)算法.webp docs/03编程语言/Java/02JVM/assets/垃圾回收算法/标记-清除算法 1.webp docs/03编程语言/Java/02JVM/assets/垃圾回收算法/标记-清除算法.png docs/03编程语言/Java/02JVM/assets/垃圾回收算法/标记-清除算法.webp docs/03编程语言/Java/02JVM/assets/未命名/Java 应用线上问题排查思路、工具小结本文总结了一些Java应用线上常见问题的定位步骤,分享的主要目的是想让对线上问题 - 掘金.mhtml docs/03编程语言/Java/02JVM/判断对象存活算法.md docs/03编程语言/Java/02JVM/双亲委派模型.md docs/03编程语言/Java/02JVM/垃圾回收算法.md docs/03编程语言/Java/02JVM/未命名.md docs/03编程语言/Java/02JVM/类加载机制.md docs/03编程语言/Java/03Java并发/Java修饰词synchronized.md docs/03编程语言/Java/03Java并发/Java修饰词volatile.md docs/03编程语言/Java/03Java并发/Q:SimpleDateFormat线程不安全,如何解决?.md docs/03编程语言/Java/03Java并发/Q:临界区与临界资源的区别?.md docs/03编程语言/Java/03Java并发/Q:并发与并行的区别?.md docs/03编程语言/Java/03Java并发/Q:并发编程需要注意哪些问题?.md docs/03编程语言/Java/03Java并发/assets/管程模型与等待-通知机制/MESA模型.png docs/03编程语言/Java/03Java并发/assets/管程模型与等待-通知机制/java中的管程.png docs/03编程语言/Java/03Java并发/assets/管程模型与等待-通知机制/等待-通知机制.png docs/03编程语言/Java/03Java并发/assets/线程安全问题的根源:可见性、原子性、有序性/可见性1.png docs/03编程语言/Java/03Java并发/assets/线程安全问题的根源:可见性、原子性、有序性/可见性2.png docs/03编程语言/Java/03Java并发/assets/线程封闭与ThreadLocal类/TreadLocal.png docs/03编程语言/Java/03Java并发/死锁的条件与解决.md docs/03编程语言/Java/03Java并发/管程模型与等待-通知机制.md docs/03编程语言/Java/03Java并发/线程安全问题的根源:可见性、原子性、有序性.md docs/03编程语言/Java/03Java并发/线程封闭与ThreadLocal类.md
- Loading branch information
Showing
51 changed files
with
295 additions
and
70,924 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
70,916 changes: 0 additions & 70,916 deletions
70,916
.../02JVM/assets/未命名/Java 应用线上问题排查思路、工具小结本文总结了一些Java应用线上常见问题的定位步骤,分享的主要目的是想让对线上问题 - 掘金.mhtml
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
|
||
## 引用计数法 | ||
|
||
问题:循环引用。 | ||
存在问题:循环引用。 | ||
|
||
## 根可达法 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
 | ||
|
||
 | ||
|
||
如果一个类收到一个类加载请求,首先会委派给父加载器去完成,如果加载过,则直接返回,如果父加载器无法完成,则再由子加载器完成加载操作。 | ||
|
||
目的,保证java的稳定性,如Object类通过双亲委派模型只能由启动类加载器加载,这就避免了出现多个Object类被加载的可能。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
生命周期:加载、验证、准备、解析、初始化、使用、卸载。其中验证、准备、解析称为类加载的连接阶段,为JVM控制执行。 | ||
|
||
## 加载 | ||
|
||
将外部的二进制类字节流按照jvm所设定的格式存储在方法区,并在堆中生成一个java.lang.Class类的对象,作为程序访问方法区中的类型数据的外部接口 | ||
|
||
## 验证 | ||
|
||
连接阶段的第一步,确保Class文件的字节流中包含的信息符合Java虚拟机规范的约束条件 | ||
|
||
## 准备 | ||
|
||
为类中的静态变量分配内存与设置初始值 | ||
|
||
## 解析 | ||
|
||
将常量池中的符号引用(Class文件中)转化为直接引用(实际JVM内存中) | ||
|
||
## 初始化 | ||
|
||
初始化阶段即为执行类构造器`<cinit>()`方法的过程,`<cinit>()`方法包含静态变量的赋值操作、静态语句块。 | ||
|
||
注意:类构造器`<cinit>()`方法不同于类的构造函数。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
分为类锁和对象锁,且有两种形式,分为方法形式和代码块形式。 | ||
|
||
当修饰静态方法时,锁定的是当前类的Class对象。 | ||
|
||
当修饰普通方法时,锁定的是当前类的实例对象。 | ||
|
||
类或对象就是加锁解锁的对象,也就是临界区。 | ||
|
||
类锁是这个类中多有实例对象都可见的锁。 | ||
|
||
对象锁仅这个对象可见。 | ||
|
||
加锁时选择什么粒度的锁取决于临界区内资源共同可见的层级在哪里,如果在同一个对象中,则加对象锁,如果在同一个类中,则加类锁,如果分属于不同的对象,则加一个全局锁(可以设置一个单例对象,或final对象)。 | ||
|
||
**synchronized锁是可重入的**,这就是说,如果线程a,已经持有锁1,则线程a再次获取锁1,仍然可以获取,jvm会将计数器加1,当释放锁的时候,计数器减1,如果计数器减到0,则说明线程a对锁1已经完全释放,其他线程可以获取锁1了。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
并不是Java语言的特产,古老的C语言里也有,它最原始的意义就是禁用CPU缓存。 | ||
|
||
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: | ||
|
||
1)**保证**了不同线程对这个变量进行操作时的**可见性**,禁用CPU缓存,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。 | ||
|
||
2)**禁止**进行指令**重排序**。 | ||
|
||
很少使用,除非能够清晰简单的解决某些问题,否则避免使用。 | ||
|
||
加锁机制既可以保证可见性,又可以保证原子性,而volatile只能保证可见性。 | ||
|
||
一个使用的例子: | ||
|
||
```java | ||
volatile boolean asleep; | ||
//doSomething(); | ||
while(!asleep) | ||
countSheep(); | ||
``` |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
临界资源是指每次仅允许一个线程访问的资源。 | ||
|
||
属于临界资源的硬件有打印机、磁带机等,软件有消息缓冲队列、变量、数组、缓冲区等。 | ||
|
||
每个线程中访问临界资源的那段代码称为临界区。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
如果某个系统支持两个或者多个动作**同时存在**,那么这个系统就是一个并发系统。 | ||
|
||
如果某个系统支持两个或者多个动作**同时执行**,那么这个系统就是一个并行系统。 | ||
|
||
**“并行”概念是“并发”概念的一个子集**。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
|
||
## 安全性问题 | ||
|
||
所谓安全性问题,就是指有没有按照预期执行。需要规避可见性、原子性、有序性上的问题。 | ||
|
||
并发的对共享数据进行读写操作时,就需要考虑安全性问题。 | ||
|
||
数据竞争:当多个线程同时访问同一数据,并且至少有一个线程会写这个数据的时候。 | ||
|
||
竞态条件:程序的执行结果依赖线程执行的顺序。 | ||
|
||
常见的竞态条件类型: | ||
|
||
- 先检查后执行 | ||
- 读取-写入-修改 | ||
|
||
解决方案:互斥锁。 | ||
|
||
## 活跃性问题 | ||
|
||
死锁:指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 | ||
|
||
解决方案:破坏死锁的形成条件。 | ||
|
||
活锁:指线程1可以使用资源,但它很礼貌,让其他线程先使用资源,线程2也可以使用资源,但它很绅士,也让其他线程先使用资源。这样你让我,我让你,最后两个线程都无法使用资源。 | ||
|
||
解决方案:尝试等待一个随机的时间。 | ||
|
||
饥饿:指的是线程因无法访问所需资源而无法执行下去的情况。 | ||
|
||
解决方案:有三种方案,一是保证资源充足,二是公平地分配资源,三就是避免持有锁的线程长时间执行。其中方案二的适用场景相对来说更多一些,如使用公平锁。 | ||
|
||
## 性能问题 | ||
|
||
如果锁使用过度,导致串行范围过大,则无法发挥多线程的优势,将产生性能问题。 | ||
|
||
解决方案: | ||
|
||
一,使用无锁算法和数据结构:例如线程本地存储(ThreadLocalStorage、TLS)、写入时复制(Copy-on-write)、乐观锁等;Java 并发包里面的原子类也是一种无锁的数据结构;Disruptor 则是一个无锁的内存队列,性能都非常好。 | ||
|
||
二,减少锁持有的时间:例如使用细粒度的锁,一个典型的例子就是 Java 并发包里的 ConcurrentHashMap,它使用了所谓分段锁的技术;还可以使用读写锁,也就是读是无锁的,只有写的时候才会互斥。 | ||
|
||
# 编写并发程序的一些建议 | ||
|
||
1.优先使用成熟的工具类:JavaSDK并发包里提供了丰富的工具类,基本上能满足你日常需要。 | ||
|
||
2.迫不得已时才使用低级的同步原语:低级的同步原语主要指的是 synchronized、Lock、Semaphore 等,这些虽然感觉简单,但实际上并没那么简单,一定要小心使用。 | ||
|
||
3.避免过早优化:安全第一,并发程序首先要保证安全,出现性能瓶颈后再优化。 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
一组互相竞争资源 的线程因互相等待,导致“永久”阻塞的现象。 | ||
|
||
死锁发生的四个必要条件: | ||
|
||
1. 互斥条件:一个资源每次只能被一个进程使用。 | ||
2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 | ||
3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 | ||
4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 | ||
|
||
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。 | ||
|
||
死锁的避免: | ||
|
||
反过来分析,也就是说只要我们破坏其中一个,就可以成功避免死锁的发生。 其中,互斥这个条件我们没有办法破坏,因为我们用锁为的就是互斥。不过其他三个条件都是有办法破坏掉的,到底如何做呢? | ||
|
||
1. 对于“请求与保持”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。 | ||
2. 对于“不剥夺”这个条件,占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。 | ||
3. 对于“循环等待”这个条件,可以靠按序申请资源来预防。所谓按序申请,是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不 存在循环了。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
|
||
## 等待-通知机制 | ||
|
||
线程首先获取互斥锁,当线程要求的条件不满足时,释放互斥锁,进入等待状态;当要求的条件满足时,通知等待的线程,重新获取互斥锁。 | ||
|
||
使用 synchronized 配合 wait()、notify()、notifyAll() 这三个方法就可以实现等待-通知机制。notify() 是会随机地通知等待队列中的一个线程,而 notifyAll() 会通知等待队列中的所有线程(除非经过深思熟虑,否则尽量使用 notifyAll() )。 | ||
|
||
 | ||
|
||
```java | ||
public class Allocator { | ||
private List<Object> als; | ||
|
||
//申请资源(一次性申请所有资源) | ||
synchronized void apply(Object from, Object to) { | ||
//有可能唤醒后条件再次不满足,所以需要while循环 | ||
while (als.contains(from) || als.contains(to)) { | ||
try { | ||
wait(); | ||
} catch (Exception e) { | ||
//do sth. | ||
} | ||
} | ||
als.add(from); | ||
als.add(to); | ||
} | ||
|
||
//归还资源 | ||
synchronized void free(Object from, Object to) { | ||
als.remove(from); | ||
als.remove(to); | ||
notifyAll(); | ||
} | ||
} | ||
``` | ||
|
||
## 管程 | ||
|
||
所谓管程(Monitor,有翻译为监视器),指的是管理共享变量以及对共享变量的操作过程,让它们支持并发。 | ||
|
||
并发编程里两大核心问题——互斥和同步,都可以由管程来帮你解决。 | ||
|
||
管程是一个抽象概念,synchronized 就是 java 针对管程的一种实现。 | ||
|
||
在管程的发展史上,先后出现过三种不同的管程模型,分别是:Hasen 模型、Hoare 模型和 MESA 模型。Java 参考的是 MESA 模型来实现管程。 | ||
|
||
 | ||
|
||
Java内置的管程方案(synchronized)使用简单,synchronized 关键字修饰的代码块,在编译期会自动生成相关加锁和解锁的代码,但是仅支持一个条件变量: | ||
|
||
 | ||
|
||
MESA中 wait() 的编程范式,是在一个 while 循环中调用 wait()。 | ||
|
||
```java | ||
while(条件不满足){ | ||
wait(); | ||
} | ||
``` | ||
|
||
除非经过深思熟虑,否则尽量使用 notifyAll()。 | ||
|
||
如果要使用 notify() 则需要满足下面的条件: | ||
|
||
1. 所有等待线程拥有相同的等待条件; | ||
2. 所有等待线程被唤醒后,执行相同的操作; | ||
3. 只需要唤醒一个线程。 | ||
|
||
```java | ||
static class BlockingQ { | ||
private static final int MAX_SIZE = 10; | ||
private final List<String> queue = new ArrayList<>(MAX_SIZE); | ||
|
||
public void put(String s) throws InterruptedException { | ||
synchronized (queue) { | ||
while (queue.size() >= MAX_SIZE) | ||
queue.wait(); | ||
queue.add(s); | ||
queue.notifyAll(); | ||
} | ||
} | ||
|
||
public String get() throws InterruptedException { | ||
synchronized (queue) { | ||
while (queue.isEmpty()) { | ||
queue.wait(); | ||
} | ||
String result = queue.remove(0); | ||
queue.notifyAll(); | ||
return result; | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
**缓存**导致了可见性问题,**线程切换**带来了原子性问题,**编译优化**带来了有序性问题 | ||
|
||
## 可见性 | ||
|
||
一个线程对共享变量的修改,另外一个线程能够立刻看到,我们称为**可见性**。 | ||
|
||
单核CPU不存在可见性问题: | ||
|
||
 | ||
|
||
多核CPU可能存在可见性问题: | ||
|
||
 | ||
|
||
线程A和线程B同时拿到了变量V的缓存,但其中一个线程对V的修改,不会马上让另一个线程知晓,从而后写入内存的会覆盖先写入的值。 | ||
|
||
## 原子性 | ||
|
||
我们把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为**原子性**。 | ||
|
||
在32位系统中,long类型变量的赋值操作不具有原子性,一个long变量占64位,如果在更改变量值时,刚更改完前32位,就被别的线程抢占,那么此时后32位还没来得及更改,造成赋值错误。 | ||
|
||
## 有序性 | ||
|
||
编译器为了优化性能,可能会调整语句的先后顺序,从而造成**有序性**问题。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
|
||
局部变量存储在各自线程的独立栈空间中,不与其他线程共享,所以不存在安全性问题,这称为线程封闭。 | ||
|
||
数据库连接池里获取的连接Connection,就采用线程封闭技术,在Connection释放前,不会分配给其他线程,从而保证了安全性。 | ||
|
||
## Ad-hoc线程封闭 | ||
|
||
就是通过编码保证线程封闭,这就会有风险。 | ||
|
||
## 栈封闭 | ||
|
||
栈封闭简单理解就是通过局部变量来实现线程封闭,多个线程访问对象的同一个方法,方法内部的局部变量会拷贝到每个线程的线程栈当中,只有当前线程才能访问到,互不干扰。所以局部变量是不被多个线程所共享的。 | ||
|
||
## ThreadLocal类 | ||
|
||
维护线程封闭一种更规范的方法就是使用ThreadLocal。ThreadLocal提供get和set方法,这些方法为每个使用该变量的线程都存有一份独立的副本因此get总是返回的是当前线程在调用set时设置的值。 | ||
|
||
 |