1、多线程编程-1-如何减少上下文切换
我们在使用多线程时,不是多线程就能提升程序的执行速度,程序在执行时,多线程 是 CPU通过给每个线程分配CPU时间片来实现的,时间片 是CPU分配给每个线程执行的时间,因时间片非常短,所以CPU通过不停地切换线程执行。
什么是上下文切换:
操作系统中,CPU时间分片切换到另一个就绪的线程,则需要保存当前线程的运行的位置,同时需要加载需要恢复线程的环境信息。
什么情况下会触发上下文切换:
1、中断请求2、多任务执行(时间分片切换) 3、用户态切换;
在中断处理中,其他程序”打断”了当前正在运行的程序。当CPU接收到中断请求时,会在正在运行的程序和发起中断请求的程序之间进行一次上下文切换。
在多任务处理中,CPU会在不同程序之间来回切换,每个程序都有相应的处理时间片,CPU在两个时间片的间隔中进行上下文切换。
对于一些操作系统,当进行用户态切换时也会进行一次上下文切换,虽然这不是必须的。
上下文切换对性能的影响:
好,即然上下文切换是有性能损耗的,那么我们如何减少上下文切换呢。
如何减少上下文切换:
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少的线程和使用协程
l 无锁并发编程。多线程竞争时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,将数据Id按hash算法取模来分段,不同的线程处理不同时端的数据
l CAS算法。Java的atomic包使用CAS算法来更新数据,面不需要加锁。Atomic变量的更新可以实现数据操作的原子性及可见性。这个是由volatile 原语及CPU的CAS指令来实现的。
l 使用最少的线程。若任务少,但创建了很多线程来处理,这样会造成大量的线程处于等等状态。
l 协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间切换。java语言级别原生并不支持协程,可以看下kilim,利用java增强字节码实现角色模型(actor)
查看jvm中线程的状态及执行情况
u 查看java的pid:Ps –ef|grep java
u 用jstack dump 线程的信息
[root@localhost bin]# /usr/java/jdk1.7.0_67/bin/jstack 5152>5152.dump
u 统计各状态的线程数量
[root@localhost bin]# grepjava.lang.Thread.Stat 5152.dump |awk '{print$2$3$4$5}'|sort|uniq –c
查看上下文切换的次数
利用jstack –l pid查看线程的状态信息(在windos在任务管理器中查看java 的PID,linux用ps –ef查看)
例子:死锁
public classDeadLockDemo {
private static StringA="A";
private static String B="B";
public static void main(String[] args){
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread thread = new Thread(newRunnable() {
public void run() {
synchronized (A) {
try {
Thread.currentThread().sleep(2000);
} catch(InterruptedExceptione) {
e.printStackTrace();
}
synchronized (B) {
System.out.println(1);
}
}
}
});
Thread thread1 = newThread(newRunnable() {
public void run() {
synchronized (B) {
synchronized (A) {
System.out.println("2");
}
}
}
});
thread.start();
thread1.start();
}
}
线程 信息如下:
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.thread.test.DeadLockDemo$2.run(DeadLockDemo.java:31)
- waiting to lock <0x00000007c0987e08> (a java.lang.String)
- locked <0x00000007c0987e38> (a java.lang.String)
at java.lang.Thread.run(Thread.java:724)
"Thread-0":
at com.thread.test.DeadLockDemo$1.run(DeadLockDemo.java:22)
- waiting to lock <0x00000007c0987e38> (a java.lang.String)
- locked <0x00000007c0987e08> (a java.lang.String)
at java.lang.Thread.run(Thread.java:724)
Found 1 deadlock.