java的上下文切換
多線程一定比單線程快嗎?
這個(gè)答案是否定的,在一定情況下,單線程是比多線程執(zhí)行效率更高的
影響多線程執(zhí)行效率有一個(gè)關(guān)鍵因素:上下文切換
什么是上下文切換?
cpu通過給每個(gè)線程分配時(shí)間片來實(shí)現(xiàn)多線程,而時(shí)間片就是cpu分配給每個(gè)線程執(zhí)行的時(shí)間(通常為幾十毫秒);而在切換前,會(huì)保存程序當(dāng)前的執(zhí)行狀態(tài),以備cpu再次切換到該線程時(shí)候加載當(dāng)前狀態(tài)繼續(xù)往下執(zhí)行,保存與加載的這個(gè)過程被稱為是程序的上下文切換。
public class SpeedTest { private static final Long count = 10000L; public static void main(String[] args) throws InterruptedException { concurrency(); serial(); } private static void concurrency() throws InterruptedException { long start = System.currentTimeMillis(); Thread test = new Thread(new Runnable() { public void run() { int a = 0; for (long i = 0; i < count; i++) { a += 5; } } }, "test"); test.start(); int b = 0; for (long j = 0; j < count; j++) { b--; } long end = System.currentTimeMillis() - start; test.join(); System.out.println("多線程" + end); } 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 j = 0; j < count; j++) { b--; } long end = System.currentTimeMillis() - start; System.out.println("單線程" + end); } }
以上代碼是java并發(fā)編程書籍上的測試案例
| 循環(huán)次數(shù) | 單線程執(zhí)行時(shí)間/ms | 多線程執(zhí)行時(shí)間/ms | 并發(fā)與單線程速度相比 |
| 一億 | 111 | 74 | 多線程快37ms |
| 一千萬 | 15 | 11 | 多線程快34ms |
| 一百萬 | 8 | 7 | 多線程快1ms(幾乎接近了) |
| 十萬 | 4 | 4 | 速度相等 |
| 一萬 | 1 | 2 | 單線程快1ms |
| 一千 | 0 | 2 | 單線程快2ms |
親測所得:單線程不一定就比多線程快,這是因?yàn)槎嗑€程有上下文切換的開銷
在代碼中如何可以減少上下文切換的次數(shù)呢?
1、無鎖并發(fā)編程:多線程競爭鎖時(shí)會(huì)產(chǎn)生上下文切換,所以在使用多線程處理數(shù)據(jù)時(shí),可以使用一些辦法來避免使用鎖,例如將數(shù)據(jù)的ID按照hash算法來取模分段,不同線程處理不同的數(shù)據(jù)。
2、CAS算法:java的Atomic包使用CAS算法來更新數(shù)據(jù),而不使用加鎖
3、是用最少線程:避免創(chuàng)建不必要的線程,比如任務(wù)很少,但是創(chuàng)建了很多的線程來處理,這樣會(huì)造成大量線程處于等待狀態(tài)
4、協(xié)程:在單線程里面實(shí)現(xiàn)多任務(wù)的調(diào)度,并在單個(gè)線程里維持多個(gè)任務(wù)間的切換

浙公網(wǎng)安備 33010602011771號(hào)