1. 程式人生 > >Java 多執行緒 自定義執行緒輔助

Java 多執行緒 自定義執行緒輔助

之前的文章我介紹了C#版本的多執行緒和自定義執行緒處理器。

接下來我們來看看Java版本的呢

java 的執行緒和C#的執行緒有點區別,java的執行緒沒有是否是後臺執行緒一說,具體原因是java的執行緒是jvm的c++程式碼模擬執行緒,而C#的執行緒也是C++模擬執行緒。但是區別在於C#的執行緒會基於系統的執行緒。

C# 的 Thread.IsBackground;

這裡唯一的區別在於,C#開啟執行緒如果是非後臺執行緒即便是你關閉了程式,如果不是強制退出程序的情況下。執行緒還會繼續執行,知道垃圾回收機制強制回收。如果設定了後臺執行緒標識,關閉程式就直接退出。

java沒有一說。

java執行緒有分組和底層執行緒ID一說。C#沒有。

java的執行緒可以自定義執行緒執行介面 Runnable 或者 重寫執行緒run()方法。

其實這些都是大同小異的,區別性不大。

java執行緒的基礎知識,到處都是,我不在BB

直接開始整體吧~!

  1 /**
  2  * 執行緒模型
  3  *
  4  * @author 失足程式設計師
  5  * @Blog http://www.cnblogs.com/ty408/
  6  * @mail [email protected]
  7  * @phone 13882122019
  8  *
  9  */
 10 public class ThreadModel extends
Thread { 11 12 private static final Logger log = Logger.getLogger(TaskModel.class); 13 private static int threadID = 0; 14 private static final Object SYN_OBJECT = new Object(); 15 private long tid; 16 /** 17 * 任務列表 執行緒安全的任務列表 18 */ 19 protected final
List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>()); 20 //false標識刪除執行緒 21 private boolean runing = true; 22 23 public ThreadModel(ThreadGroup group) { 24 this(group, "無名"); 25 } 26 27 public ThreadModel(ThreadGroup group, String name) { 28 super(group, name); 29 synchronized (SYN_OBJECT) { 30 threadID++; 31 tid = threadID; 32 } 33 } 34 35 @Override 36 public long getId() { 37 return this.tid; 38 } 39 40 /** 41 * 增加新的任務 每增加一個新任務,都要喚醒任務佇列 42 * 43 * @param runnable 44 */ 45 public void addTask(TaskModel runnable) { 46 synchronized (taskQueue) { 47 taskQueue.add(runnable); 48 /* 喚醒佇列, 開始執行 */ 49 taskQueue.notify(); 50 } 51 } 52 53 public void setRuning(boolean runing) { 54 this.runing = runing; 55 } 56 57 @Override 58 public void run() { 59 while (runing && ThreadManager.getInstance().isRunning()) { 60 TaskModel r = null; 61 while (taskQueue.isEmpty() && runing && ThreadManager.getInstance().isRunning()) { 62 try { 63 /* 任務佇列為空,則等待有新任務加入從而被喚醒 */ 64 synchronized (taskQueue) { 65 taskQueue.wait(500); 66 } 67 } catch (InterruptedException ie) { 68 log.error(ie); 69 } 70 } 71 synchronized (taskQueue) { 72 /* 取出任務執行 */ 73 if (runing && ThreadManager.getInstance().isRunning()) { 74 r = taskQueue.remove(0); 75 } 76 } 77 if (r != null) { 78 /* 執行任務 */ 79 //r.setSubmitTimeL(); 80 long submitTime = System.currentTimeMillis(); 81 try { 82 r.run(); 83 } catch (Exception e) { 84 log.error("工人<“" + Thread.currentThread().getName() + "”> 執行任務<" + r.getID() + "(“" + r.getName() + "”)> 遇到錯誤: " + e); 85 e.printStackTrace(); 86 } 87 long timeL1 = System.currentTimeMillis() - submitTime; 88 long timeL2 = System.currentTimeMillis() - r.getSubmitTime(); 89 if (timeL1 <= 100L) { 90 log.info("工人<“" + Thread.currentThread().getName() + "”> 完成了任務:" + r.toString() + " 執行耗時:" + timeL1 + " 提交耗時:" + timeL2); 91 } else if (timeL1 <= 1000L) { 92 log.info("工人<“" + Thread.currentThread().getName() + "”> 長時間執行 完成任務:" + r.toString() + " “考慮”任務指令碼邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2); 93 } else if (timeL1 <= 4000L) { 94 log.info("工人<“" + Thread.currentThread().getName() + "”> 超長時間執行完成 任務:" + r.toString() + " “檢查”任務指令碼邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2); 95 } else { 96 log.info("工人<“" + Thread.currentThread().getName() + "”> 超長時間執行完成 任務:" + r.toString() + " “考慮是否應該刪除”任務指令碼 耗時:" + timeL1 + " 提交耗時:" + timeL2); 97 } 98 r = null; 99 } 100 } 101 log.error("執行緒結束, 工人<“" + Thread.currentThread().getName() + "”>退出"); 102 } 103 104 @Override 105 public String toString() { 106 return "Thread{" + "tid=" + tid + ",Name=" + this.getName() + '}'; 107 } 108 109 }

這裡建立我們自定義的執行緒模型,有兩點值得注意的是,

protected final List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>());
synchronized (taskQueue) {
            taskQueue.add(runnable);
            /* 喚醒佇列, 開始執行 */
            taskQueue.notify();
        }

synchronized (taskQueue) {
                        taskQueue.wait(500);
                    }

這裡我們同樣沒有使用Thread.Sleep();對執行緒進行暫停,同樣使用的是 taskQueue.wait();來進行執行緒暫停,這是因為當任務佇列為空的時候,需要暫停執行緒。

當新的任務被放進來的時候,又必須立即開始執行任務。

為了防止執行緒永久暫停,設定的是500毫秒,這樣我們需要關閉程式(ThreadManager.getInstance().isRunning()==false)停止執行緒時候他會自定停止。

輔助鍵值對儲存器

  1 /**
  2  * 輔助鍵值對儲存
  3  *
  4  * @author 失足程式設計師
  5  * @Blog http://www.cnblogs.com/ty408/
  6  * @mail [email protected]
  7  * @phone 13882122019
  8  */
  9 public class ObjectAttribute extends HashMap<String, Object> {
 10 
 11     private static final long serialVersionUID = -5320260807959251398L;
 12 
 13     /**
 14      * 呼叫此方法 刪除值是需要保證存在key值和value值 否則空指標報錯
 15      *
 16      * @param <T>
 17      * @param key
 18      * @param clazz
 19      * @return
 20      * @deprecated 需要保證存在key值和value值 否則空指標報錯 慎重
 21      */
 22     @Deprecated
 23     public <T extends Object> T remove(String key, Class<T> clazz) {
 24         Object obj = this.remove(key);
 25         return (T) obj;
 26     }
 27 
 28     /**
 29      * 如果未找到也返回 null
 30      *
 31      * @param key
 32      * @return
 33      */
 34     public String getStringValue(String key) {
 35         if (this.containsKey(key)) {
 36             return this.get(key).toString();
 37         }
 38         return null;
 39     }
 40 
 41     /**
 42      * 如果未找到也返回 0
 43      *
 44      * @param key
 45      * @return
 46      */
 47     public int getintValue(String key) {
 48         if (this.containsKey(key)) {
 49             return (int) (this.get(key));
 50         }
 51         return 0;
 52     }
 53 
 54     /**
 55      * 如果未找到也返回 null
 56      *
 57      * @param key
 58      * @return
 59      */
 60     public Integer getIntegerValue(String key) {
 61         if (this.containsKey(key)) {
 62             return (Integer) (this.get(key));
 63         }
 64         return null;
 65     }
 66 
 67     /**
 68      * 如果未找到也返回 0
 69      *
 70      * @param key
 71      * @return
 72      */
 73     public long getlongValue(String key) {
 74         if (this.containsKey(key)) {
 75             return (long) (this.get(key));
 76         }
 77         return 0;
 78     }
 79 
 80     /**
 81      * 如果未找到也返回 null
 82      *
 83      * @param key
 84      * @return
 85      */
 86     public Long getLongValue(String key) {
 87         if (this.containsKey(key)) {
 88             return (Long) (this.get(key));
 89         }
 90         return null;
 91     }
 92 
 93     /**
 94      * 如果未找到也返回 0
 95      *
 96      * @param key
 97      * @return
 98      */
 99     public float getfloatValue(String key) {
100         if (this.containsKey(key)) {
101             return (float) (this.get(key));
102         }
103         return 0;
104     }
105 
106     /**
107      * 如果未找到也返回 null
108      *
109      * @param key
110      * @return
111      */
112     public Float getFloatValue(String key) {
113         if (this.containsKey(key)) {
114             return (Float) (this.get(key));
115         }
116         return null;
117     }
118 
119     /**
120      * 如果未找到也返回 false
121      *
122      * @param key
123      * @return
124      */
125     public boolean getbooleanValue(String key) {
126         if (this.containsKey(key)) {
127             return (boolean) (this.get(key));
128         }
129         return false;
130     }
131 
132     /**
133      * 如果未找到也返回 null
134      *
135      * @param key
136      * @return
137      */
138     public Boolean getBooleanValue(String key) {
139         if (this.containsKey(key)) {
140             return (Boolean) (this.get(key));
141         }
142         return null;
143     }
144 
145     @Override
146     public Object clone() {
147         return super.clone(); //To change body of generated methods, choose Tools | Templates.
148     }
149 }
View Code

任務執行模型

 1 /**
 2  * 任務模型
 3  *
 4  * @author 失足程式設計師
 5  * @Blog http://www.cnblogs.com/ty408/
 6  * @mail [email protected]
 7  * @phone 13882122019
 8  *
 9  */
10 public abstract class TaskModel {
11 
12     private static final Logger log = Logger.getLogger(TaskModel.class);
13 
14     private long ID;
15     private String Name;
16     //執行時資料
17     private ObjectAttribute runAttribute = new ObjectAttribute();
18 
19     public TaskModel(long ID, String Name) {
20         this.ID = ID;
21         this.Name = Name;
22         this.runAttribute.put("submitTime", System.currentTimeMillis());
23     }
24 
25     public TaskModel() {
26         this(0, "無名");
27     }
28 
29     public long getSubmitTime() {
30         return this.runAttribute.getlongValue("submitTime");
31     }
32 
33     public ObjectAttribute getRunAttribute() {
34         return runAttribute;
35     }
36 
37     public void setRunAttribute(ObjectAttribute runAttribute) {
38         this.runAttribute = runAttribute;
39     }
40 
41     public long getID() {
42         return ID;
43     }
44 
45     public String getName() {
46         return Name;
47     }
48 
49     public abstract void run();
50 
51     @Override
52     public String toString() {
53         return "TaskModel{" + "ID=" + ID + ", Name=" + Name + ", runAttribute=" + runAttribute + '}';
54     }
55 
56 }

接下來我們測試一下

1   ThreadModel threadModel = new ThreadModel(new ThreadGroup("Test"), "Test");
2         threadModel.start();
3         threadModel.addTask(new TaskModel() {
4 
5             @Override
6             public void run() {
7                 System.out.println("TaskModel Test");
8             }
9         });

執行結果

TaskModel Test
[04-24 17:31:26:0223:INFO : sz.network.threadpool.TaskModel:97 行] -> 工人<“Test”> 完成了任務:TaskModel{ID=0, Name=無名, runAttribute={submitTime=1429867886219}} 執行耗時:0 提交耗時:4

我們看到居然有提交耗時,,別奇怪,,因為在某些情況下,執行緒的從暫停狀態到喚醒狀態需要消耗時間的,系統不可能有那麼多空閒資源,收到你的命令馬上就放棄一切事情執行你的命令。

我們除錯執行時可以看見當前程式所有執行緒,以及分組情況(我使用的是NetBeans IDE 8.0.2 開發工具)

接下來我們來構建一下。後臺執行緒池,

 1 /**
 2  * 後臺執行緒池
 3  *
 4  * @author 失足程式設計師
 5  * @Blog http://www.cnblogs.com/ty408/
 6  * @mail [email protected]
 7  * @phone 13882122019
 8  */
 9 class BackThread {
10 
11     private static final Logger log = Logger.getLogger(BackThread.class);
12 
13     private final ThreadGroup threadGroup = new ThreadGroup(ThreadManager.getGlobeThreadGroup(), "後臺執行器");
14 
15     /* 任務列表 */
16     private final List<TaskModel> taskQueue = Collections.synchronizedList(new LinkedList<TaskModel>());
17     private final BackThreadRunnable backThreadRunnable = new BackThreadRunnable();
18 
19     public BackThread() {
20         int threadcountI = 10;
21         for (int i = 1; i <= threadcountI; i++) {
22             Thread thread = new Thread(threadGroup, backThreadRunnable, "後臺執行緒-" + i);
23             thread.start();
24         }
25         log.info("---初始化後臺執行緒池--執行緒數量:" + threadcountI + "------------");
26     }
27 
28     /**
29      * 增加新的任務 每增加一個新任務,都要喚醒任務佇列
30      *
31      * @param newTask
32      */
33     public void addTask(TaskModel newTask) {
34         synchronized (taskQueue) {
35             taskQueue.add(newTask);
36             /* 喚醒佇列, 開始執行 */
37             taskQueue.notify();
38         }
39     }
40 
41     final class BackThreadRunnable implements Runnable {
42 
43         /**
44          * 迴圈執行任務
45          */
46         @Override
47         public void run() {
48             while (ThreadManager.getInstance().isRunning()) {
49                 TaskModel r = null;
50                 synchronized (taskQueue) {
51                     while (taskQueue.isEmpty() && ThreadManager.getInstance().isRunning()) {
52                         try {
53                             /* 任務佇列為空,則等待有新任務加入從而被喚醒 */
54                             taskQueue.wait(500);
55                         } catch (InterruptedException ie) {
56                             log.error(ie);
57                         }
58                     }
59                     /* 取出任務執行 */
60                     if (ThreadManager.getInstance().isRunning()) {
61                         r = taskQueue.remove(0);
62                     }
63                 }
64                 if (r != null) {
65                     /* 執行任務 */
66                     //r.setSubmitTimeL();
67                     long submitTime = System.currentTimeMillis();
68                     try {
69                         r.run();
70                     } catch (Exception e) {
71                         e.printStackTrace();
72                         log.error("工人<“" + Thread.currentThread().getName() + "”> 執行任務<" + r.getID() + "(“" + r.getName() + "”)> 遇到錯誤: " + e);
73                     }
74                     long timeL1 = System.currentTimeMillis() - submitTime;
75                     long timeL2 = System.currentTimeMillis() - r.getSubmitTime();
76                     if (timeL1 <= 100L) {
77                         log.info("工人<“" + Thread.currentThread().getName() + "”> 完成了任務:" + r.toString() + " 執行耗時:" + timeL1 + " 提交耗時:" + timeL2);
78                     } else if (timeL1 <= 1000L) {
79                         log.info("工人<“" + Thread.currentThread().getName() + "”> 長時間執行 完成任務:" + r.toString() + " “考慮”任務指令碼邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2);
80                     } else if (timeL1 <= 4000L) {
81                         log.info("工人<“" + Thread.currentThread().getName() + "”> 超長時間執行完成 任務:" + r.toString() + " “檢查”任務指令碼邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2);
82                     } else {
83                         log.info("工人<“" + Thread.currentThread().getName() + "”> 超長時間執行完成 任務:" + r.toString() + " “考慮是否應該刪除”任務指令碼 耗時:" + timeL1 + " 提交耗時:" + timeL2);
84                     }
85                     r = null;
86                 }
87             }
88             log.error("執行緒結束, 工人<“" + Thread.currentThread().getName() + "”>退出");
89         }
90     }
91 }

以及定時器執行緒處理器

 1 /**
 2  * 定時器執行緒
 3  *
 4  * @author 失足程式設計師
 5  * @Blog http://www.cnblogs.com/ty408/
 6  * @mail [email protected]
 7  * @phone 13882122019
 8  */
 9 class TimerThread extends ThreadModel {
10 
11     private static final Logger log = Logger.getLogger(TimerThread.class);
12 
13     public TimerThread() {
14         super(ThreadManager.getGlobeThreadGroup(), "全域性定時器執行緒");
15         this.start();
16     }
17 
18     @Override
19     public void run() {
20         while (ThreadManager.getInstance().isRunning()) {
21             while (ThreadManager.getInstance().isRunning() && taskQueue.isEmpty()) {
22                 try {
23                     /* 任務佇列為空,則等待有新任務加入從而被喚醒 */
24                     synchronized (taskQueue) {
25                         taskQueue.wait(200);
26                     }
27                 } catch (InterruptedException ie) {
28                 }
29             }
30             ArrayList<TaskModel> taskModels;
31             synchronized (taskQueue) {
32                 //佇列不為空的情況下  取出佇列定時器任務
33                 taskModels = new