剛開始接觸java的時候免不了對多線程技術總是懷抱着好奇心,總想弄明白多線程好在哪裏。甚至於認爲使用多線程效率就比單線程要高。但事實真的如此嗎?下面我們做一些測試
測試1-單線程執行效率
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
System.out.println("開啓1個線程...");
// 創建一個線程池
ExecutorService pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
for (int i = 0; i <dataSize ; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//當調用shutdown()方法後,並且所有提交的任務完成後,isTerminated()返回爲true;
pool.shutdown();
while (true) {
if (pool.isTerminated()) {//所有的子線程都結束了
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
測試2-多線程執行效率(5個線程異步執行)
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
// 每1000條數據開啓一條線程
int threadSize = 1000;
// 線程數
int threadNum = dataSize / threadSize;
System.out.println("開啓" + threadNum + "個線程...");
ExecutorService pool = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
// 分割成多個線程執行
for (int i = 0; i < dataSize; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
測試3-多線程執行效率(50個線程異步執行)
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
// 每100條數據開啓一條線程
int threadSize = 100;
// 線程數
int threadNum = dataSize / threadSize;
System.out.println("開啓" + threadNum + "個線程...");
ExecutorService pool = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
// 分割成多個線程執行
for (int i = 0; i < dataSize; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
測試4-多線程執行效率(500個線程異步執行)
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
// 每10條數據開啓一條線程
int threadSize = 10;
// 線程數
int threadNum = dataSize / threadSize;
System.out.println("開啓" + threadNum + "個線程...");
ExecutorService pool = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
// 分割成多個線程執行
for (int i = 0; i < dataSize; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
測試5-多線程執行效率(1000個線程異步執行)
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
// 每5條數據開啓一條線程
int threadSize = 5;
// 線程數
int threadNum = dataSize / threadSize;
System.out.println("開啓" + threadNum + "個線程...");
ExecutorService pool = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
// 分割成多個線程執行
for (int i = 0; i < threadNum; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
測試6-多線程執行效率(5000個線程異步執行)
public static void main(String[] args) {
Long start = System.currentTimeMillis();
// 總數據條數
int dataSize = 5000;
// 每1條數據開啓一條線程
int threadSize = 1;
// 線程數
int threadNum = dataSize / threadSize;
System.out.println("開啓" + threadNum + "個線程...");
ExecutorService pool = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
// 分割成多個線程執行
for (int i = 0; i < threadNum; i++) {
//放到線程池中,線程異步執行
pool.execute(new Thread() {
@Override
public void run() {
try {
//模擬業務處理數據的時間
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
break;
}
}
Long end = System.currentTimeMillis();
System.out.println("總共花費了===========" + (end - start) / 1000 + "." + (end - start) % 1000 + "s");
}
結果:
數據分析
1個線程---------------54.554s
5個線程---------------10.947s
50個線程--------------1.139s
500個線程-------------0.182s
1000個線程-----------0.158s
5000個線程-----------0.579s
總結:
多線程的確可以提高併發任務處理效率,特別是初期線程數慢慢提高的時候。但隨着線程數大幅的提高效率卻降低了。在我本地測試的線程數到達5000個的時候明顯效率還不如500個~。這是因爲每臺計算機都有其性能瓶頸,開多少線程效率最高, 和線程的任務利用何種部件,以及這些部件的獨立/共享狀態相關。至於能運行多少個線程與你運行的程序有關,你可以用以下代碼在自己電腦上測試可以開到多少個線程(謹慎使用)。
private static Object object = new Object();
private static int count = 0;
public static void main(String[] args) {
for(;;){
new Thread(new Runnable(){
public void run(){
synchronized(object){
count += 1;
System.err.println("New thread #"+count);
}
for(;;){
try {
Thread.sleep(1000);
} catch (Exception e){
System.err.println(e);
}
}
}
}).start();
}
}
我用jdk1.8 + windows10 + 4核CPU + 8G內存 最多到 172020 的時候就死機了~