故:大多数时间CPU都都在等待。多核心CPU,CPU闲置更多。
推荐阅读:我是一个CPU:这个世界慢!死!了!
CPU在执行A任务(A没有执行完)时,切换到任务B,需要保存A的上下文内容,等待CPU切换到执行A任务使用。需要消耗大概1000个时钟周期。
不是说多线程是可以提高效率,怎么又说多线程慢呢。这里慢单纯指的是线程之间切换时消耗的时间和CPU的时钟周期相比慢。针对内存寻址、硬盘寻址是有提升的。
协程–>用户态线程。需要重写调度器。
查看一下Thread 和 runable callable等穿件线程方法类或接口的注释,就清晰说明只有Thread实例才代表JVM中的线程。
代码 while (true) { i++;} 会在Thread线程和主线程中同时访问变量i。
public static int i =0;
public static void main(String[] args) {
//Thread线程
new Thread(() -> {
while (true) {
i++;
}
}).start();
//主线程
while (true) {
i++;
}
}
doSomething到底在哪个线程执行?
答案是不确定。doSomething不是线程,仅仅是个任务。哪个线程执行取决于它的实现。假如线程池满了,可以让调用的线程执行。
public class ThreadTest {
static ExecutorService threadPool = Executors.newCachedThreadPool();
static int i =0;
public static void main(String[] args) {
threadPool.submit(()->{
//doSomething到底在哪个线程执行? 答案是不确定。取决于它的实现。
//假如线程池满了,可以让调用的线程执行。
doSomething();
});
doSomething();
}
private static void doSomething(){
i++;
}
}
线程Thread和主线程同时在执行doSomething。
如果doSomething更复杂一点呢。
你脑袋里面时刻要想象两个线程同时在执行,执行到哪儿。
public class ThreadTest02 {
static int i = 0;
public static void main(String[] args) {
//Thread线程
new Thread(()->{
doSomething();
}).start();
//主线程
doSomething();
}
private static void doSomething(){
i++;
}
}
线程的异常只会抛出到它自己的方法栈中,不能夸方法栈抛异常。
主线程中的catch只能捕获主线程中抛出的异常。
public class ThreadTest04 {
static int i = 0;
public static void main(String[] args) {
try {
new Thread(() -> {
//该异常只会抛出到它自己的方法栈中,不能夸方法栈抛异常
throw new RuntimeException();
}).start();
} catch (Exception e) {
//catch只能捕获主线程中抛出的异常。
e.printStackTrace();
}
doSomething();
}
private static void doSomething() {
i++;
}
}
public static enum State {
/**
* A Thread which has not yet started.
*/
NEW,
/**
* A Thread which is running or suspended.
*/
RUNNABLE,
/**
* A Thread which is blocked on a monitor.
*/
BLOCKED,
/**
* A Thread which is waiting with no timeout.
*/
WAITING,
/**
* A Thread which is waiting with a timeout.
*/
TIMED_WAITING,
/**
* A thread which is no longer alive.
*/
TERMINATED }
调用线程的不同 返回不同的值。主线程和Thread线程调用返回不同的值。
public class ThreadTest05 {
static MyThreadLocal threadLocal =new MyThreadLocal();
public static void main(String[] args) {
threadLocal.set("main主线程");
new Thread(()->{
threadLocal.set("Thread线程");
doSomething();
}).start();
doSomething();
}
private static void doSomething(){
System.out.println("Thread:"+Thread.currentThread().getName()+":"+threadLocal.get());
}
private static class MyThreadLocal{
Map<Long,String> data =new HashMap<>();
public String get(){
return data.get(Thread.currentThread().getId());
}
public void set(String userName){
data.put(Thread.currentThread().getId(), userName);
}
}
}
输出:
Thread:main:main主线程
Thread:Thread-2:Thread线程
模拟登录存储用户信息,使用拦截器,调用set方法即可。
ThreadLocal中没有上面MyThreadLocal时的map对象,那么它的值存在什么地方?存在ThreadLocalMap里面。
/**
* 当前登录用户的信息 使用拦截器
*/
static class UserContext{
static ThreadLocal<Integer> threadLocal =new ThreadLocal<>();
public void set (Integer userId){
threadLocal.set(userId);
}
public Integer get(){
return threadLocal.get();
}
}
操作系统内核线程的缺点:
携程:
携程解决的问题:多线程调度慢,占用资源多大额问题。
携程未解决的问题:并发问题,死锁,竞争条件。