1、上下文切换
即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现 这个机制。这个时间片特别短,一般是几十毫秒,所以会让我们觉得好多任务同时进行。 CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个 任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这 个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。,例如:
当我们在读一本英文的技术书时,发现某个单词不认识,于是 便打开中英文字典,但是在放下英文技术书之前,大脑必须先记住这本书读到了多少页的第 多少行,等查完单词之后,能够继续读这本书
2、多线程一定快吗
我们用一段代码来查看多线程并发是否就一定比串行快
public class ConcurrencyTest {private static final long count = 1000000L;public static void main(String[] args) throws Exception{concurrentcy();; //并发执行程序serial(); //串行方法}private static void concurrentcy() throws Exception {long start = System.currentTimeMillis(); //获取当前系统时间Thread thread = new Thread(() -> {int a = 0;for (long i = 0; i < count; i++) {a += 5;}});thread.start();int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;thread.join();System.out.println(String.format("concurrecy: %dms, b=%d", time, b));}private static void serial() {long start = System.currentTimeMillis();int a = 0;for (long i = 0; i < count; i++) {a += 5;}int b = 0;for (long i = 0; i < count; i++) {b --;}long time = System.currentTimeMillis() - start;System.out.println(String.format("serial: %dms, b=%d", time, b));}
}
在我们对count值更改多次后,得出结论如下:
显然,当任务次数在低于1百万时,串行的效率是比并发要高的,这是什么原因呢?因为并发线程有创建和上下文切换的开 销。
减少上下文切换的方法:
3、死锁DeadLock
死锁是指多个进程在运行过程中因争夺资源而造成的一种僵局,若无外力帮助,则它们都无法继续向前推进,直到程序崩溃为止。我们举一个例子:
public class DeadLockTest {public static Object A = new Object();public static Object B = new Object();public static void main(String[] args) {new Thread(()->{synchronized (A){System.out.println(Thread.currentThread().getName()+"获取了资源A的锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (B){System.out.println(Thread.currentThread().getName()+"获取了资源B的锁");}}}).start();new Thread(()->{synchronized (B){System.out.println(Thread.currentThread().getName()+"获取了资源A的锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (A){System.out.println(Thread.currentThread().getName()+"获取了资源B的锁");}}}).start();}}```- 该类中,两个线程会发生死锁,因为程序启动时,两个线程几乎同时对A与B上锁,然后又几乎同时开始申请B与A资源,此时便发生了死锁,此时想要解决的话只能从外部强行把发生死锁的进程进行终止,windows的方法如下
首先,使用jps查看java所运行的线程信息,如下
我么可以看到共有4个,然后使用jstack查看线程信息
-
可以发现,Thread-0与Thread-1是处于locked状态,也就是发生了死锁,此时再执行taskkill /F /PID来将死锁的线程强行终止