Thread与ThreadLocal
2020-07-22 本文已影响0人
叫我C30混凝土
- Thread类的每一个实例代表一个JVM中的线程
- 在Linux上称为'轻量级进程',和进程无本质区别,所以又统称为task即任务;(区别:仅仅是线程共享内存,而进程不共享内存),多个线程共享一份内存时,称为process group(进程组);
以下代码为例:
- 在Linux上称为'轻量级进程',和进程无本质区别,所以又统称为task即任务;(区别:仅仅是线程共享内存,而进程不共享内存),多个线程共享一份内存时,称为process group(进程组);
public class ThreadClass {
static int i = 0;
public static void main(String[] args) {
new Thread(() -> {
doSomething();
return;
}).start();
doSomething();
}
private static void doSomething() {
while (true) {
i++;
}
}
}
代码Linux进程.jpg
↑↑↑Linux中线程也拥有独立的pid(jps查询java进程id,再用pstree查询该进程由哪些线程组成)
- 在windows上使用系统线程
优点:
简单,直接依赖操作系统的调度器;
缺点:
占用资源多;每个JVM的线程都映射到Linux系统的内核线程,内核线程都有一套独立的方法栈,会占用空间;
上下文切换慢;CPU切换不同任务时,每次都要发起不同的系统调用,并发起环境保存,下一次恢复的时候,还需要把环境从内存中取出;
不灵活,无法实现灵活的优先级;JVM线程的调度非常依赖内核线程,没有办法灵活分配线程的占用资源或调整优先级;
Thread的生命周期
Thread生命周期.jpg代码地址:java.lang.Thread.State
public enum State {
/**
* Thread state for a thread which has not yet started.
* 新创建的线程
*/
NEW,//
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
* 这个线程可能正在JVM执行,也可能在等待CPU资源/IO;
* 等待IO过程: RUNNABLE发起IO状态--> Linux的open系统调用
* -->CPU发现需要进行IO操作,就先去执行了其他操作,导致CPU虽然
* 放弃该线程,但是线程依旧处于RUNNABLE状态;而当系统收到IO中
* 断信号时,才去真正执行操作;(操作系统通过中断方式实现IO)
* 虽然操作系统处于阻塞状态,但是在JVM眼中,依旧是RUNNABLE;
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
* JVM中仅用来指代synchronized (锁)状态,
* PS:monitor 称为监视器,synchronized 可以锁住一个monitor(当前对
* 象或全局对象); 和操作系统中的阻塞状态没有任何关系;
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*
* 如果对象Object被synchronized 锁住之后,其他人也想要用,就需要
* 进入WAIT_QUEUE等待队列中;
*
* WAITING 和 TIMED_WAITING仅指一堆线程等待一个对象的状态;
* WAITING 和 TIMED_WAITING的区别,在于TIMED_WAITING有超
* 时操作Object#wait(long);
* Object.wait(),notify()方法,是最初JVM设计中用于线程协同所用的状
* 态;但是jdk1.5后设计了一套Lock和Condition来提供同样的功能;
*
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
* 线程执行完成后的状态;
*/
TERMINATED;
}
ThreadLocal
- 当不同的线程共同调用heap(堆)中的同一个对象,希望不同线程返回不同结果,就需要使用ThreadLocal;
- 通常用于储存线程私有的值,方便后续流程使用;
java.lang.ThreadLocal
/**
* This class provides thread-local variables.
这个类提供线程局部变量
* {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
ThreadLocal实例通常是private static 变量,它能使每个线程拥有一个不同的状态;例如:user ID or Transaction ID;
* <p>Each thread holds an implicit reference to its copy of a thread-local
* variable as long as the thread is alive and the {@code ThreadLocal}
* instance is accessible; after a thread goes away, all of its copies of
* thread-local instances are subject to garbage collection (unless other
* references to these copies exist).
只要每个线程还活着,那么每一个线程都拥有一个隐式的拷贝;当一个线程结束,所有的拷贝都会被GC(除非还有其他地方引用这份拷贝);
结论:所以在ThreadLocal代码中并没有map ,而是放在了Thread中;
*/
↑↑↑ThreadLocal代码注释
public class ThreadClass {
static MyThreadLocal threadLocal = new MyThreadLocal();
public static void main(String[] args) {
threadLocal.set("user2");
new Thread(() -> {
threadLocal.set("user1");
doSomething();
}).start();
doSomething();
}
private static void doSomething() {
System.out.println("thread:" + Thread.currentThread().getName() + ":" + threadLocal.get());
}
// 实现简易ThreadLocal
private static class MyThreadLocal {
//key:threadId,value:用户名
Map<Long, String> map = new ConcurrentHashMap<>();
public String get() {
return map.get(Thread.currentThread().getId());
}
public void set(String userName) {
map.put(Thread.currentThread().getId(), userName);
}
}
}
// 结果
thread:main:user2
thread:Thread-0:user1
栈针
栈针包含局部变量表与操作数栈,是执行字节码所需要的信息;