問題背景:
目前需要解析十多個Excel文件並將數據導入到數據庫,文件導出完成之后還有后續步驟需要處理,例如更新批次狀態。
如果采用單線程的方式順序去處理每個文件的話,感覺有點慢,雖說不算是特別慢,但是由於用戶需要等待導入結果,
考慮到用於體驗問題,因此需要坐下性能優化。既然是性能優化,基本都是考慮到使用多線程並發處理
。但是多線線程有個問題,
就是啟動多個線程后,如何讓當前線程等待這些子線程執行完畢,因為需要根據所以子線程的執行結果來更新批次狀態
解決方案1:
基本思路是這樣:
每個SubThread子線程類實例有個自己的狀態
99-初始化 0-執行成功 1-執行失敗,當執行完畢之后,將狀態修改為0或者1
MainThread
主線程類中有個List,用來登記所有子線程。子線程的創建通過主線程來創建,每次創建之后,都會將子線程添加到List中。
所有子線程創建完成之后,通過主線程的start方法啟動所有子線程,並通過一個while循環來遍歷List中的所有子線程的狀態,
判斷是否存在狀態為99的,如果沒有,則便是全部子線程執行完畢
/**
* 子線程類
* @author Administrator
*
*/
public class SubThread implements Runnable{
private int status = 99; //99-初始化 0-執行成功 1-執行失敗
public void run() {
System.out.println("開始執行...");
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
status=0;
System.out.println("執行完畢...");
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
} |
/**
* 主線程類
* @author Administrator
*
*/
public class MainThread {
private List<SubThread> subThreadList = new ArrayList<SubThread>();
/**
* 創建子線程
* @return
*/
public SubThread createSubThread(){
SubThread subThread = new SubThread();
subThreadList.add(new SubThread());
return subThread;
}
public boolean start(){
for(SubThread subThread : subThreadList){
new Thread(subThread).start();
}
/**
* 監控所有子線程是否執行完畢
*/
boolean continueFlag = true;
while(continueFlag){
for(SubThread subThread : subThreadList){
if(subThread.getStatus()==99){
continueFlag = true;
break;
}
continueFlag = false;
}
}
/**
* 判斷子線程的執行結果
*/
boolean result = true;
for(SubThread subThread : subThreadList){
if(subThread.getStatus()!=0){
result = false;
break;
}
}
return result;
}
|
測試代碼:
public static void main(String[] args) {
MainThread main = new MainThread();
main.createSubThread();
main.createSubThread();
main.createSubThread();
boolean result = main.start();
System.out.println(result);
}
|
解決方案2:
通過計數器方式解決。
基本思路如下:
計數器類
CountLauncher
負責記錄正在執行的子線程的總數,所有的子線程共享該計數器類對象,當子線程執行完畢之后,調用計數器的counDown()方法進行計數器減1.
主線程通過計數器類來判斷是否所有子線程都執行完畢。
/**
* 計數器類
* @author Administrator
*
*/
public class CountLauncher {
private int count;
public CountLauncher(int count){
this.count = count;
}
public synchronized void countDown(){
count --;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
} |
/**
* 子線程類
* @author Administrator
*
*/
public class SubThread implements Runnable{
/**
* 計數器類對象實例
*/
private CountLauncher countLauncher;
private int status = 99; //99-初始化 0-執行成功 1-執行失敗
public void run() {
System.out.println("開始執行...");
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
status=0;
System.out.println("執行完畢...");
countLauncher.countDown();
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public CountLauncher getCountLauncher() {
return countLauncher;
}
public void setCountLauncher(CountLauncher countLauncher) {
this.countLauncher = countLauncher;
}
|
/**
* 主線程類
* @author Administrator
*
*/
public class MainThread {
private List<SubThread> subThreadList = new ArrayList<SubThread>();
/**
* 創建子線程
* @return
*/
public synchronized SubThread createSubThread(){
SubThread subThread = new SubThread();
subThreadList.add(new SubThread());
return subThread;
}
public boolean start(){
CountLauncher countLauncher = new CountLauncher(subThreadList.size());
for(SubThread subThread : subThreadList){
subThread.setCountLauncher(countLauncher);
new Thread(subThread).start();
}
while(countLauncher.getCount()>0){
System.out.println(countLauncher.getCount());
}
/**
* 判斷子線程的執行結果
*/
boolean result = true;
for(SubThread subThread : subThreadList){
if(subThread.getStatus()!=0){
result = false;
break;
}
}
return result;
}
/**
*
測試實例
*/
public static void main(String[] args) {
MainThread main = new MainThread();
main.createSubThread();
main.createSubThread();
main.createSubThread();
boolean result = main.start();
System.out.println(result);
}
|
解決方案3(推薦):
該方法的處理方式同解決方案2 ,只不過使用的是Java自帶的計數器類
java.util.concurrent.CountDownLatch。
還有一點就是不需要在主線程中通過while來監控所有子線程,是否通過調用它的await方法進行等待所有子線程的執行完畢。
使用計數器時,需要注意的一點是:子線程中調用countDown()方法時一定要放在最后來執行,否則會出現子線程未執行完畢,主線程就開始往下執行了。
因為一定計數器為0,就會自動喚醒主線程的。
/**
* 子線程
* @author Administrator
*
*/
public class SubThread implements Runnable{
private int status =99;
private CountDownLatch threadsSignal;
@Override
public void run(){
System.out.println("開始執行...");
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
status=0;
System.out.println("執行完畢...");
threadsSignal.countDown();
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public CountDownLatch getThreadsSignal() {
return threadsSignal;
}
public void setThreadsSignal(CountDownLatch threadsSignal) {
this.threadsSignal = threadsSignal;
}
} |
public class MainThread {
public List<SubThread> subThreadList = new ArrayList<SubThread>();
/**
* 創建子線程
* @param clazzPath
* @param methodName
* @return
*/
public SubThread createSubThread(){
SubThread subThread = new SubThread();
subThreadList.add(subThread);
return subThread;
}
/**
* 啟動線程
*/
public int start() throws Exception{
CountDownLatch threadSignal = new CountDownLatch(subThreadList.size());
for(SubThread subThread :subThreadList){
subThread.setThreadsSignal(threadSignal);
Thread thread = new Thread(subThread);
thread.start();
}
threadSignal.await();
System.out.println("所有子線程執行完畢...");
for(SubThread subThread :subThreadList){
if(subThread.getStatus()!=0){
return 1;
}
}
return 0;
}
public static void main(String[] args) throws Exception{
MainThread main = new MainThread();
main.createSubThread();
main.createSubThread();
main.createSubThread();
main.createSubThread();
int result = main.start();
System.out.println("執行結果:" + result);
}
|