国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java多線程優化方法及使用方式

Java多線程優化方法及使用方式

2021-03-31 13:40我心自在 Java教程

這篇文章主要介紹了Java多線程優化方法及使用方式,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

一、多線程介紹

在編程中,我們不可逃避的會遇到多線程的編程問題,因為在大多數的業務系統中需要并發處理,如果是在并發的場景中,多線程就非常重要了。另外,我們在面試的時候,面試官通常也會問到我們關于多線程的問題,如:如何創建一個線程?我們通常會這么回答,主要有兩種方法,第一種:繼承thread類,重寫run方法;第二種:實現runnable接口,重寫run方法。那么面試官一定會問這兩種方法各自的優缺點在哪,不管怎么樣,我們會得出一個結論,那就是使用方式二,因為面向對象提倡少繼承,盡量多用組合。

這個時候,我們還可能想到,如果想得到多線程的返回值怎么辦呢?根據我們多學到的知識,我們會想到實現callable接口,重寫call方法。那么多線程到底在實際項目中怎么使用呢,他有多少種方式呢?

首先,我們來看一個例子:

Java多線程優化方法及使用方式

這是一種創建多線程的簡單方法,很容易理解,在例子中,根據不同的業務場景,我們可以在thread()里邊傳入不同的參數實現不同的業務邏輯,但是,這個方法創建多線程暴漏出來的問題就是反復創建線程,而且創建線程后還得銷毀,如果對并發場景要求低的情況下,這種方式貌似也可以,但是高并發的場景中,這種方式就不行了,因為創建線程銷毀線程是非常耗資源的。所以根據經驗,正確的做法是我們使用線程池技術,jdk提供了多種線程池類型供我們選擇,具體方式可以查閱jdk的文檔。

Java多線程優化方法及使用方式

這里代碼我們需要注意的是,傳入的參數代表我們配置的線程數,是不是越多越好呢?肯定不是。因為我們在配置線程數的時候要充分考慮服務器的性能,線程配置的多,服務器的性能未必就優。通常,機器完成的計算是由線程數決定的,當線程數到達峰值,就無法在進行計算了。如果是耗cpu的業務邏輯(計算較多),線程數和核數一樣就到達峰值了,如果是耗i/o的業務邏輯(操作數據庫,文件上傳、下載等),線程數越多一定意義上有助于提升性能。

線程數大小的設定又一個公式決定:

y=n*((a+b)/a),其中,n:cpu核數,a:線程執行時程序的計算時間,b:線程執行時,程序的阻塞時間。有了這個公式后,線程池的線程數配置就會有約束了,我們可以根據機器的實際情況靈活配置。

二、多線程優化及性能比較

最近的項目中用到了所線程技術,在使用過程中遇到了很多的麻煩,趁著熱度,整理一下幾種多線程框架的性能比較。目前所掌握的大致分三種,第一種:threadpool(線程池)+countdownlatch(程序計數器),第二種:fork/join框架,第三種jdk8并行流,下面對這幾種方式的多線程處理性能做一下比較總結。

首先,假設一種業務場景,在內存中生成多個文件對象,這里暫定30000,(thread.sleep(時間))線程睡眠模擬業務處理業務邏輯,來比較這幾種方式的多線程處理性能。

1) 單線程

這種方式非常簡單,但是程序在處理的過程中非常的耗時,使用的時間會很長,因為每個線程都在等待當前線程執行完才會執行,和多線程沒有多少關系,所以效率非常低。

首先創建文件對象,代碼如下:

java" id="highlighter_113611">
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class fileinfo {
 private string filename;//文件名
 private string filetype;//文件類型
 private string filesize;//文件大小
 private string filemd5;//md5碼
 private string fileversionno;//文件版本號
 public fileinfo() {
  super();
 }
 public fileinfo(string filename, string filetype, string filesize, string filemd5, string fileversionno) {
  super();
  this.filename = filename;
  this.filetype = filetype;
  this.filesize = filesize;
  this.filemd5 = filemd5;
  this.fileversionno = fileversionno;
 }
 public string getfilename() {
  return filename;
 }
 public void setfilename(string filename) {
  this.filename = filename;
 }
 public string getfiletype() {
  return filetype;
 }
 public void setfiletype(string filetype) {
  this.filetype = filetype;
 }
 public string getfilesize() {
  return filesize;
 }
 public void setfilesize(string filesize) {
  this.filesize = filesize;
 }
 public string getfilemd5() {
  return filemd5;
 }
 public void setfilemd5(string filemd5) {
  this.filemd5 = filemd5;
 }
 public string getfileversionno() {
  return fileversionno;
 }
 public void setfileversionno(string fileversionno) {
  this.fileversionno = fileversionno;
 }

接著,模擬業務處理,創建30000個文件對象,線程睡眠1ms,之前設置的1000ms,發現時間很長,整個eclipse卡掉了,所以將時間改為了1ms。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class test {
   private static list<fileinfo> filelist= new arraylist<fileinfo>();
   public static void main(string[] args) throws interruptedexception {
     createfileinfo();
     long starttime=system.currenttimemillis();
     for(fileinfo fi:filelist){
       thread.sleep(1);
     }
     long endtime=system.currenttimemillis();
     system.out.println("單線程耗時:"+(endtime-starttime)+"ms");
   }
   private static void createfileinfo(){
     for(int i=0;i<30000;i++){
       filelist.add(new fileinfo("身份證正面照","jpg","101522","md5"+i,"1"));
     }
   }
}

測試結果如下:

Java多線程優化方法及使用方式

可以看到,生成30000個文件對象消耗的時間比較長,接近1分鐘,效率比較低。

2) threadpool (線程池) +countdownlatch (程序計數器)

顧名思義,countdownlatch為線程計數器,他的執行過程如下:首先,在主線程中調用await()方法,主線程阻塞,然后,將程序計數器作為參數傳遞給線程對象,最后,每個線程執行完任務后,調用countdown()方法表示完成任務。countdown()被執行多次后,主線程的await()會失效。實現過程如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class test2 {
 private static executorservice executor=executors.newfixedthreadpool(100);
 private static countdownlatch countdownlatch=new countdownlatch(100);
 private static list<fileinfo> filelist= new arraylist<fileinfo>();
 private static list<list<fileinfo>> list=new arraylist<>();
 public static void main(string[] args) throws interruptedexception {
  createfileinfo();
  addlist();
  long starttime=system.currenttimemillis();
  int i=0;
  for(list<fileinfo> fi:list){
   executor.submit(new filerunnable(countdownlatch,fi,i));
   i++;
  }
  countdownlatch.await();
  long endtime=system.currenttimemillis();
  executor.shutdown();
  system.out.println(i+"個線程耗時:"+(endtime-starttime)+"ms");
 }
 private static void createfileinfo(){
  for(int i=0;i<30000;i++){
   filelist.add(new fileinfo("身份證正面照","jpg","101522","md5"+i,"1"));
  }
 }
 private static void addlist(){
  for(int i=0;i<100;i++){
   list.add(filelist);
  }
 }
}

filerunnable類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * 多線程處理
 * @author wangsj
 *
 * @param <t>
 */
public class filerunnable<t> implements runnable {
   private countdownlatch countdownlatch;
   private list<t> list;
   private int i;
   public filerunnable(countdownlatch countdownlatch, list<t> list, int i) {
     super();
     this.countdownlatch = countdownlatch;
     this.list = list;
     this.i = i;
   }
   @override
   public void run() {
     for(t t:list){
       try {
          thread.sleep(1);
       } catch (interruptedexception e) {
          e.printstacktrace();
       }
       countdownlatch.countdown();
     }
   }
}

測試結果如下:

Java多線程優化方法及使用方式

3) fork/join 框架

jdk從版本7開始,出現了fork/join框架,從字面來理解,fork就是拆分,join就是合并,所以,該框架的思想就是。通過fork拆分任務,然后join來合并拆分后各個人物執行完畢后的結果并匯總。比如,我們要計算連續相加的幾個數,2+4+5+7=?,我們利用fork/join框架來怎么完成呢,思想就是拆分子任務,我們可以把這個運算拆分為兩個子任務,一個計算2+4,另一個計算5+7,這是fork的過程,計算完成后,把這兩個子任務計算的結果匯總,得到總和,這是join的過程。

fork/join框架執行思想:首先,分割任務,使用fork類將大任務分割為若干子任務,這個分割過程需要按照實際情況來定,直到分割出的任務足夠小。然后,join類執行任務,分割的子任務在不同的隊列里,幾個線程分別從隊列里獲取任務并執行,執行完的結果放到一個單獨的隊列里,最后,啟動線程,隊列里拿取結果并合并結果。

使用fork/join框架要用到幾個類,關于類的使用方式可以參考jdk的api,使用該框架,首先需要繼承forkjointask類,通常,只需要繼承他的子類recursivetask或recursiveaction即可,recursivetask,用于有返回結果的場景,recursiveaction用于沒有返回結果的場景。forkjointask的執行需要用到forkjoinpool來執行,該類用于維護分割出的子任務添加到不同的任務隊列。

下面是實現代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class test3 {
 private static list<fileinfo> filelist= new arraylist<fileinfo>();
// private static forkjoinpool forkjoinpool=new forkjoinpool(100);
// private static job<fileinfo> job=new job<>(filelist.size()/100, filelist);
 public static void main(string[] args) {
  createfileinfo();
  long starttime=system.currenttimemillis();
  forkjoinpool forkjoinpool=new forkjoinpool(100);
  //分割任務
  job<fileinfo> job=new job<>(filelist.size()/100, filelist);
  //提交任務返回結果
forkjointask<integer> fjtresult=forkjoinpool.submit(job);
//阻塞
  while(!job.isdone()){
   system.out.println("任務完成!");
  }
  long endtime=system.currenttimemillis();
  system.out.println("fork/join框架耗時:"+(endtime-starttime)+"ms");
 }
 private static void createfileinfo(){
  for(int i=0;i<30000;i++){
   filelist.add(new fileinfo("身份證正面照","jpg","101522","md5"+i,"1"));
  }
 }
}
/**
 * 執行任務類
 * @author wangsj
 *
 */
public class job<t> extends recursivetask<integer> {
 private static final long serialversionuid = 1l;
 private int count;
 private list<t> joblist;
 public job(int count, list<t> joblist) {
  super();
  this.count = count;
  this.joblist = joblist;
 }
 /**
  * 執行任務,類似于實現runnable接口的run方法
  */
 @override
 protected integer compute() {
  //拆分任務
  if(joblist.size()<=count){
   executejob();
   return joblist.size();
  }else{
   //繼續創建任務,直到能夠分解執行
   list<recursivetask<long>> fork = new linkedlist<recursivetask<long>>();
   //拆分子任務,這里采用二分法
   int countjob=joblist.size()/2;
   list<t> leftlist=joblist.sublist(0, countjob);
   list<t> rightlist=joblist.sublist(countjob, joblist.size());
   //分配任務
   job leftjob=new job<>(count,leftlist);
   job rightjob=new job<>(count,rightlist);
   //執行任務
   leftjob.fork();
   rightjob.fork();
   return integer.parseint(leftjob.join().tostring())
     +integer.parseint(rightjob.join().tostring());
  }
 }
 /**
  * 執行任務方法
  */
 private void executejob() {
  for(t job:joblist){
   try {
    thread.sleep(1);
   } catch (interruptedexception e) {
    e.printstacktrace();
   }
  }
 }

測試結果如下:

Java多線程優化方法及使用方式

4) jdk8 并行流

并行流是jdk8的新特性之一,思想就是將一個順序執行的流變為一個并發的流,通過調用parallel()方法來實現。并行流將一個流分成多個數據塊,用不同的線程來處理不同的數據塊的流,最后合并每個塊數據流的處理結果,類似于fork/join框架。

并行流默認使用的是公共線程池forkjoinpool,他的線程數是使用的默認值,根據機器的核數,我們可以適當調整線程數的大小。線程數的調整通過以下方式來實現。

?
1
system.setproperty("java.util.concurrent.forkjoinpool.common.parallelism", "100");

以下是代碼的實現過程,非常簡單:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class test4 {
private static list<fileinfo> filelist= new arraylist<fileinfo>();
public static void main(string[] args) {
//    system.setproperty("java.util.concurrent.forkjoinpool.common.parallelism", "100");
   createfileinfo();
   long starttime=system.currenttimemillis();
   filelist.parallelstream().foreach(e ->{
     try {
        thread.sleep(1);
     } catch (interruptedexception f) {
        f.printstacktrace();
     }
   });
   long endtime=system.currenttimemillis();
   system.out.println("jdk8并行流耗時:"+(endtime-starttime)+"ms");
}
private static void createfileinfo(){
   for(int i=0;i<30000;i++){
     filelist.add(new fileinfo("身份證正面照","jpg","101522","md5"+i,"1"));
   }
}
}

下面是測試,第一次沒有設置線程池的數量,采用默認,測試結果如下:

Java多線程優化方法及使用方式

我們看到,結果并不是很理想,耗時較長,接下來設置線程池的數量大小,即添加如下代碼:

?
1
system.setproperty("java.util.concurrent.forkjoinpool.common.parallelism", "100");

接著進行測試,結果如下:

Java多線程優化方法及使用方式

這次耗時較小,比較理想。

三、總結

綜上幾種情況來看,以單線程作為參考,耗時最長的還是原生的fork/join框架,這里邊盡管配置了線程池的數量,但效果較精確配置了線程池數量的jdk8并行流較差。并行流實現代碼簡單易懂,不需要我們寫多余的for循環,一個parallelstream方法全部搞定,代碼量大大的減少了,其實,并行流的底層還是使用的fork/join框架,這就要求我們在開發的過程中靈活使用各種技術,分清各種技術的優缺點,從而能夠更好的為我們服務。

原文鏈接:http://www.cnblogs.com/10158wsj/p/8338367.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 日本福利视频 | 青青草国产 | 中文字幕亚洲综合 | 欧美日韩久| 成人涩涩日本国产一区 | 日穴视频在线观看 | 精品视频久久久 | 欧美精品久久久久久久久老牛影院 | 色av成人| 亚洲精品久久久久久动漫 | 日韩三级电影在线观看 | 婷婷色av | 99国产精品99久久久久久 | 91午夜伦伦电影理论片 | 日日日日干干干干 | 国产综合久久 | 日本久久久久 | 久久久www | 亚洲成人精品av | 自拍偷拍精品 | 欧美亚洲国产激情 | 亚洲综合色视频在线观看 | 亚洲国产精品一区二区第一页 | 日韩福利片 | 欧美成人精品在线 | 国产四区 | 国产中文字幕亚洲 | 不卡视频一二三区 | 精品一区二区三区中文字幕 | 国产精品久久久久久久久久久久午夜片 | 婷婷在线视频 | 国内精品一区二区三区 | 午夜爽爽爽 | 久久精品中文字幕大胸 | 色香蕉在线 | 亚洲一本 | 久久极品 | 国产精品久久久久久久久久久久久久 | 国产尤物av| 亚洲国产网站 | 亚洲一区成人在线观看 |