- 进程是操作系统管理内存和程序的容器
- 线程是CPU运行的基础单元
- 协程是用户态的一个运行单元,它标志用户态的运行程序
wait和block的区别
- wait: 线程运行到某一阶段被执行wait函数之后,就回去竞争某一把锁,如果竞争得到,或者被notify唤醒,该线程就可以继续运行,因此wait状态可以理解我们的运行程序在遇到一些条件的时候,主动去做等待被唤醒的动作.
- block: 当我的CPU在等待某一个IO进程的时候会进入block(阻塞状态),也就是被IO block
Runnable和Callable的区别
- 共同点: 都可以是线程运行的函数
- runnable方法没有返回值,仅仅只定义了一个线程可运行的一个run方法的函数,当线程运行完的时候,无论线程内部的状态怎样,都没有办法通过返回值这样的一个通信机制,将线程内部的变量给返回出来
- callable方法可以带有一个call方法,对应一个返回值可以将线程局部变量内部的一些方法或者局部变量的一些内容给返回出来
- 一般来说,如果我们不关注线程内部的一些具体的运行,而仅仅只把它当做一个任务,我们只需要使用runnable方法即可
- 如果我们需要关注线程内部的一些内容,我们就可能需要callable方法
ThreadLocal变量的作用
ThreadLocal污染的问题
-
http client 每次请求都会对应起一个线程,ThreadLocal顾名思义,表示的是我这个线程专属本地变量的一个形式,也就是说每一次请求都会由这个线程专属的本地线程变量去做对应的操作,另一个线程过来,肯定做的是另一个线程对应的请求,这个时候它访问的就是另一个ThreadLocal变量
-
一般来说,我们的web容器肯定是带有线程池的,这个时候仍然可能出现不同http client是复用之前的线程,这就是通常所说的ThreadLocal污染的问题
-
因此 我们在做程序开发的时候都会在线程结束的时候将ThreadLocal变量设置回去
package com.restManager.shop;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName ThreadLocalTest
* @date 2021/5/18 23:52
* @Version 1.0
* @Author ShyBoy
*/
public class ThreadLocalTest {
static ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal<Map<String,Object>>(){
@Override
protected Map<String, Object> initialValue() {
return new HashMap<String,Object>();
}
};
//每一个ThreadLocal中都存有自己独有的map,互不影响
public static void main(String[] args) {
threadLocal.get().put("demo","11");
outInfo();
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.get().put("demo","22");
outInfo();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
threadLocal.get().put("demo","33");
outInfo();
}
}).start();
}
private static void outInfo() {
System.out.println(Thread.currentThread().getName()+" : "+threadLocal.get());
}
}
线程池的核心参数
ThreadPoolExecutor:
- coreSize: 核心线程数 通常也被定义为最小线程数 一般取两倍CPU个数再加1(磁盘数)
- maxSize: 最大线程数
- queueSize: 等待队列数
- keepAliveTime: 空闲线程多久被销毁
- handler: 拒绝策略,丢弃/丢弃抛异常/调用线程处理/丢弃最前面的任务然后尝试重新执行
核心参数之间的关系(考点)
- 当我们对应的线程池pool被new出来的时候,我们对应通常来说,它的线程池是一个空的线程池,然后当我有第一个请求被submit到了我这个线程池当中的时候,我们就会将对应开辟一个线程去为它服务,当有第二个请求的时候开辟第二个线程,直到开辟到coreSize的时候(前面的线程没有终止),假设coreSize=10,当有第11 个请求进来的时候,我的线程池会去看,我的之前10个线程是否都在忙,如果有不在忙碌的,则取出线程池中对应的这个线程,为这个请求服务; 如果不存在不在忙碌的线程,线程池会把这个任务扔到queue等待队列中,假设queueSize=20,,(假设前面的十个线程仍然处于忙碌状态,否则直接将非忙碌线程拿出来为这个task服务),且新任务又将等待队列塞满的时候,我们就会尝试开启新的线程,直到开到maxSize,我们对应回去执行拒绝策略handler