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来将死锁的线程强行终止