操作系统角度,线程是最小的执行单位
一个进程包含了多个线程,多个线程共用堆和方法区资源,但是每个线程有自己的计数器和栈。
看线程基本知识,描述了两者区别
线程创建有3种方式,继承Thread类,实现Runnable接口,Callable接口(又返回值)
因为jvm执行start方法时候,会先创建一条线程,由创建的线程去调用thread类的run方法,起到多线程效果,如果直接执行run方法,那么相当于还是运行在主线程中,起不到多线程作用了。
共六种状态
为了让用户感觉多个线程是在同时执行的, CPU 资源的分配采用了时间片轮转也就是给每个线程分配一个时间片,
线程在时间片内占用 CPU 执行任务。当线程使用完时间片后,就会处于就绪状态并让出 CPU 让其他线程占用,这
就是上下文切换。
Java中的线程分为两类,分别为 daemon 线程(守护线程)和 user 线程(用户线程)。
在JVM 启动时会调用 main 函数,main函数所在的线程就是一个用户线程。其实在 JVM 内部同时还启动了很多守护
线程, 比如垃圾回收线程。
那么守护线程和用户线程有什么区别呢?区别之一是当最后一个非守护线程束时, JVM会正常退出,而不管当前是否
存在守护线程,也就是说守护线程
TheadLocal是一个线程本地变量,如果你创建了一个ThreadLocal变量,那么访问这些变量的每个线程都会有这一个变量的本地拷贝,多个线程操作变量时候,实际操作的是自己本地内存里面的变量,从而起到线程隔离的作用,避免了线程的安全问题。
1.创建一个ThreadLocal线程变量
public static ThreadLocal<String> localVabile = new ThreadLocal<>();
2.写入
localVabile.set("共享资源");
3.读取,在任何一个地方读取的都是他写入的变量
localVabile.get()
查看ThreadLocal的set方法,发现是先获取当前的线程,在获取TheadLocalMap,然后再把这个元素放到map中
public void set(T value){
//获取当前线程
Thread t = Thread.currentThread();
//获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
//将当前元素存入
if(map !=null){
map。set(this,value);
}else{
createMap(t,value)
}
ThreadLocal实现的秘密都在这个 ThreadLocalMap了,
实现原理:
在jvm中,栈内存私有,存储了对象的引用,堆内存线程共享,存储了对象实例
ThreadLocalMap中使用的 key 为 ThreadLocal 的弱引用。
“弱引用:只要垃圾回收机制一运行,不管JVM的内存空间是否充足,都会回收该对象占用的内存。”
那么现在问题就来了,弱引用很容易被回收,如果ThreadLocal(ThreadLocalMap的Key)被垃圾回收?回收了,但
是ThreadLocalMap生命周期和Thread是一样的,它这时候如果不被回收,就会出现这种情况: ThreadLocalMap的
key没了,value还在,这就会造成了内存泄漏问题。使用完ThreadLocal后及时调用remove()方法释放空间。
key设计成弱引用同样是为了防止内存泄漏。
假如key被设计成强引用,如果ThreadLocal Reference被销毁,此时它指向ThreadLoca的强引用就没有了,但是此时key
还强引用指向ThreadLoca,就会导致ThreadLocal不能被回收,这时候就发生了内存泄漏的问题。
ThreadLocalMap虽然被叫做map,但是它没有实现Map接口,但是结构还是和HashMap类似的,主要就是关注的是两个元素:元素数组和散列方法
int i = key.threadLocalHashCode & (table.length - 1);
我们都知道hashmap使用了链表来解决冲突,也就是所谓的链地址法。
ThreadLocalMap则是使用的是开放定址法,简单来说就是这个坑被人占了,那就接着找个空着的坑
父线程不能使用TheadLocal来给子线程进行值传递,这个时候使用另一个类InheritableThreadLocal,再主线程的InheritablThreadLocal实例设置值,在子线程中就可以拿到
public class InheritableThreadLocalTest {
public static void main(String[] args) {
final ThreadLocal threadLocal = new InheritableThreadLocal();
// 主线程
threadLocal.set("不 技术");
//子线程
Thread t = new Thread() {
@Override
public void run()
{ super.run();
System.out.println(" 人三某 ," +
threadLocal.get());
}
};
t.start();
}
}
那原理是什么呢?
原理很简单,在Thread类里还有另外一个变量:
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
在Thread.init的时候,如果父线程的 inheritableThreadLocals 不为空,就把它赋给当前线程(子线程)的
inheritableThreadLocals 。
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
ps:给我一个一键三连加加油呢