Android線程池使用終結版

原文出處:http://mzh3344258.blog.51cto.com/1823534/1313611java


有一段時間沒寫博文了,今天抽空總結一下,也但願能經過本身寫的這些文章,加深理解的同時能幫android

助在技術方面有疑點的朋友搞清楚個因此然來,因爲常常會在網上或羣裏看到有朋友會問線程方面的網絡

東西,就像我一個朋友他們老師講的,J2SE、J2EE裏面使用的線程方面的東西可能不是太多,可是app

在Android開發裏面,玩的就是線程(UIThread)!好了,廢話就說這麼多吧,直入正題!今天要講的less

東西就是線程池、線程的高效率使用,靈活控制!今天死馬我就用最經常使用的幾種方式來分別實現應用異步

中使用的線程方面的知識,(共寫了兩個不一樣入口的Activity來分開不一樣的實現方式,你們能夠自行注ide

釋AndroidManifest.xml中的Launch入口或打開註釋)任何發代碼中的具體實現效果,好了,先隨便列佈局

幾個吧,如:AsyncTask、Runnable、Thread、ThreadPool、Executors等等的使用,看我文章的朋測試

友應該都很清楚小馬的方式啦,果斷先上效果,再一步步分解代碼,來吧,效果圖以下:ui

一:無大小限制的線程池執行效果以下

二:限制按順序來執行任務的線程池效果以下

222725754.gif

三:一個一個任務的執行線程池效果以下(與按順序執行效果是同樣的,只是內部實現稍有不一樣)

222657697.gif

四:按指定個數來執行任務的線程池效果以下

222840612.gif

五:建立一個可在指定時間裏執行任務的線程池,亦可重複執行,不經常使用,效果與四相同

222856182.gif

六:按指定工廠模式來執行的線程池,效果與4、五同樣,但用方式六建立的線程池都有在工廠

中指定的線程屬性,好比:線程名字、是否爲用戶線程等等屬性

222913795.gif

七:線程池中任務執行時可暫停效果圖以下

222933493.gif

八:用Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的效果圖以下

222950866.gif

哦的了,效果看完了,如今就請你們自行修改AndroidManifest.xml中主Activity的入口來看兩種不一樣方式實現的代碼效果吧,首先,先貼一下Main.java類的代碼,但願你們詳細看裏面的註釋,必定要詳細看,你不會吃虧的,相信我!(備註:爲了寫文章加註釋還有查找的時候方便,小馬把全部的主類及輔助類之內部類的形式寫到一個.java文件裏面了,若是朋友們以爲看着亂,不爽的話,能夠自行將裏面的類抽取到單獨的.java文件中,幾分鐘搞定的事!)

方式一(純ExecutorService、AsyncTask、Runnable關聯實現相關文件以下):

1.1:主類文件(Main.java)

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/*
* FileName:  Main.java
* CopyRight:  Belong to  <XiaoMaGuo Technologies > own
* Description:  <description>
* Modify By :  XiaoMaGuo ^_^
* Modify Date:   2013-10-15
* Follow Order No.:  <Follow Order No.>
* Modify Order No.:  <Modify Order No.>
* Modify Content:  <modify content >
*/
package com.xiaoma.threadpooltest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
/**
* @TODO [The Class File Description]
* @author XiaoMaGuo ^_^
* @version [version-code, 2013-10-15]
* @since [Product/module]
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class Main extends Activity
{
private static int order = 0;
/** 總共多少任務(根據CPU個數決定建立活動線程的個數,這樣取的好處就是可讓手機承受得住) */
// private static final int count = Runtime.getRuntime().availableProcessors() * 3 + 2;
/** 總共多少任務(我是在模擬器裏面跑的,爲了效果明顯,因此寫死了爲10個,若是在手機上的話,推薦使用上面的那個count) */
private static final int count = 10;
/** 每次只執行一個任務的線程池 */
private static ExecutorService singleTaskExecutor = null;
/** 每次執行限定個數個任務的線程池 */
private static ExecutorService limitedTaskExecutor = null;
/** 全部任務都一次性開始的線程池 */
private static ExecutorService allTaskExecutor = null;
/** 建立一個可在指定時間裏執行任務的線程池,亦可重複執行 */
private static ExecutorService scheduledTaskExecutor = null;
/** 建立一個可在指定時間裏執行任務的線程池,亦可重複執行(不一樣之處:使用工程模式) */
private static ExecutorService scheduledTaskFactoryExecutor = null;
private List<AsyncTaskTest> mTaskList = null;
/** 任務是否被取消 */
private boolean isCancled = false;
/** 是否點擊並取消任務標示符 */
private boolean isClick = false;
/** 線程工廠初始化方式一 */
ThreadFactory tf = Executors.defaultThreadFactory();
/** 線程工廠初始化方式二 */
private static class ThreadFactoryTest implements ThreadFactory
{
@Override
public Thread newThread(Runnable r)
{
Thread thread = new Thread(r);
thread.setName("XiaoMaGuo_ThreadFactory");
thread.setDaemon(true); // 將用戶線程變成守護線程,默認false
return thread;
}
}
static
{
singleTaskExecutor = Executors.newSingleThreadExecutor();// 每次只執行一個線程任務的線程池
limitedTaskExecutor = Executors.newFixedThreadPool(3);// 限制線程池大小爲7的線程池
allTaskExecutor = Executors.newCachedThreadPool(); // 一個沒有限制最大線程數的線程池
scheduledTaskExecutor = Executors.newScheduledThreadPool(3);// 一個能夠按指定時間可週期性的執行的線程池
scheduledTaskFactoryExecutor = Executors.newFixedThreadPool(3, new ThreadFactoryTest());// 按指定工廠模式來執行的線程池
scheduledTaskFactoryExecutor.submit(new Runnable()
{
@Override
public void run()
{
Log.i("KKK", "This is the ThreadFactory Test  submit Run! ! ! ");
}
});
};
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.demo);
final ListView taskList = (ListView)findViewById(R.id.task_list);
taskList.setAdapter(new AsyncTaskAdapter(getApplication(), count));
taskList.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (position == 0) // 以第一項爲例,來測試關閉線程池
{
/**
* 會關閉線程池方式一:但不接收新的Task,關閉後,正在等待 執行的任務不受任何影響,會正常執行,無返回值!
*/
// allTaskExecutor.shutdown();
/**
* 會關閉線程池方式二:也不接收新的Task,並中止正等待執行的Task(也就是說, 執行到一半的任務將正常執行下去),最終還會給你返回一個正在等待執行但線程池關閉卻沒有被執行的Task集合!
*/
List<Runnable> unExecRunn = allTaskExecutor.shutdownNow();
for (Runnable r : unExecRunn)
{
Log.i("KKK", "未執行的任務信息:=" + unExecRunn.toString());
}
Log.i("KKK", "Is shutdown ? = " + String.valueOf(allTaskExecutor.isShutdown()));
allTaskExecutor = null;
}
// 以第二項爲例來測試是否取消執行的任務
AsyncTaskTest sat = mTaskList.get(1);
if (position == 1)
{
if (!isClick)
{
sat.cancel(true);
isCancled = true;
isClick = !isClick;
}
else
{
sat.cancel(false);
isCancled = false;
// isClick = false;
isClick = !isClick;
if (null != sat && sat.getStatus() == AsyncTask.Status.RUNNING)
{
if (sat.isCancelled())
{
sat = new AsyncTaskTest(sat.mTaskItem);
}
else
{
Toast.makeText(Main.this, "A task is already running, try later", Toast.LENGTH_SHORT)
.show();
}
}
/**
* 因爲上面測試關閉,在不從新生成allTaskExecutor的同時,會報異常(沒有可使用的線程池,故此處從新生成線程池對象)
*/
if (allTaskExecutor == null)
{
allTaskExecutor = Executors.newCachedThreadPool();
}
sat.executeOnExecutor(allTaskExecutor); // The task is already running(這也是個異常哦,當心使用! )
}
}
else
{
sat.cancel(false);
isCancled = false;
// sat.execute(sat.mTaskItem);
// sat.executeOnExecutor(allTaskExecutor);
}
}
});
}
/**
* @TODO [ListView Item的條目適配器]
* @author XiaoMaGuo ^_^
* @version [version-code, 2013-10-22]
* @since [Product/module]
*/
private class AsyncTaskAdapter extends BaseAdapter
{
private Context mContext;
private LayoutInflater mFactory;
private int mTaskCount;
public AsyncTaskAdapter(Context context, int taskCount)
{
mContext = context;
mFactory = LayoutInflater.from(mContext);
mTaskCount = taskCount;
mTaskList = new ArrayList<AsyncTaskTest>(taskCount);
}
@Override
public int getCount()
{
return mTaskCount;
}
@Override
public Object getItem(int position)
{
return mTaskList.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = mFactory.inflate(R.layout.list_view_item, null);
AsyncTaskTest task = new AsyncTaskTest((MyListItem)convertView);
/**
* 下面兩種任務執行效果都同樣,形變質不變
* */
// task.execute();
// task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
/**
* 下面的方式在小於API 11級時效果是同樣的,但在高版本中的稍微有點不一樣,能夠看如下AsyncTask核心變量的定義就知道了使用以下
* 方式時,系統會默認的採用五個一組,五個一組的方式來執行咱們的任務,定義在:AsyncTask.class中,private static final int CORE_POOL_SIZE = 5;
* */
// use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11)
// but different from newer version of #execute()
// task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
/**
* 一個一個執行咱們的任務,效果與按順序執行是同樣的(AsyncTask.SERIAL_EXECUTOR)
* */
// task.executeOnExecutor(singleTaskExecutor);
/**
* 按咱們指定的個數來執行任務的線程池
* */
// task.executeOnExecutor(limitedTaskExecutor);
/**
* 不限定指定個數的線程池,也就是說:你往裏面放了幾個任務,他所有同一時間開始執行, 無論你手機受得了受不了
* */
task.executeOnExecutor(allTaskExecutor);
/**
* 建立一個可在指定時間裏執行任務的線程池,亦可重複執行
* */
// task.executeOnExecutor(scheduledTaskExecutor);
/**
* 建立一個按指定工廠模式來執行任務的線程池,可能比較正規,但也不經常使用
*/
// task.executeOnExecutor(scheduledTaskFactoryExecutor);
mTaskList.add(task);
}
return convertView;
}
}
class AsyncTaskTest extends AsyncTask<Void, Integer, Void>
{
private MyListItem mTaskItem;
private String id;
private AsyncTaskTest(MyListItem item)
{
mTaskItem = item;
if (order < count || order == count)
{
id = "執行:" + String.valueOf(++order);
}
else
{
order = 0;
id = "執行:" + String.valueOf(++order);
}
}
@Override
protected void onPreExecute()
{
mTaskItem.setTitle(id);
}
/**
* Overriding methods
*/
@Override
protected void onCancelled()
{
super.onCancelled();
}
@Override
protected Void doInVoid...  params)
{
if (!isCancelled() && isCancled == false) // 這個地方很關鍵,若是不設置標誌位的話,直接setCancel(true)是無效的
{
int prog = 0;
/**
* 下面的while中,小馬寫了個分支用來作個假象(任務東西剛開始下載的時候,速度快,快下載完成的時候就忽然間慢了下來的效果, 你們能夠想象一下,相似
* :PP手機助手、91手機助手中或其它手機應用中,幾乎都有這個假象,開始快,結束時就下載變慢了,講白了 就是開發的人不想讓你在下載到大於一半的時候,也就是快下載完的時候去點取消,你那樣得多浪費
* !因此造個假象,讓你不想去取消而已)
*/
while (prog < 101)
{
if ((prog > 0 || prog == 0) && prog < 70) // 小於70%時,加快進度條更新
{
SystemClock.sleep(100);
}
else
// 大於70%時,減慢進度條更新
{
SystemClock.sleep(300);
}
publishProgress(prog); // 更新進度條
prog++;
}
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
}
@Override
protected void onProgressUpdate(Integer... values)
{
mTaskItem.setProgress(values[0]); // 設置進度
}
}
}
/**
* @TODO [一個簡單的自定義 ListView Item]
* @author XiaoMaGuo ^_^
* @version [version-code, 2013-10-22]
* @since [Product/module]
*/
class  MyListItem  extends  LinearLayout
{
private  TextView mTitle;
private  ProgressBar mProgress;
public  MyListItem(Context context, AttributeSet attrs)
{
super (context, attrs);
}
public  MyListItem(Context context)
{
super (context);
}
public  void  setTitle(String title)
{
if  (mTitle ==  null )
{
mTitle = (TextView)findViewById(R.id.task_name);
}
mTitle.setText(title);
}
public  void  setProgress( int  prog)
{
if  (mProgress ==  null )
{
mProgress = (ProgressBar)findViewById(R.id.task_progress);
}
mProgress.setProgress(prog);
}
}

1.2:佈局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<? xml  version = "1.0"  encoding = "utf-8" ?>
< LinearLayout  xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:paddingLeft = "10dip"
android:paddingRight = "10dip"
android:orientation = "vertical"  >
< ListView  android:id = "@+id/task_list"
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:divider = "#cccccc"
android:dividerHeight = "0.6dip"
android:footerDividersEnabled = "true"
android:headerDividersEnabled = "true"  />
</ LinearLayout >

方式二(Runnable、ConcurrentLinkedQueue、ConcurrentMap、Future、ExecutorService關聯實現的相關文件以下):

2.1:主類文件(MyRunnableActivity.java)

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
* FileName:  MyRunnableActivity.java
* CopyRight:  Belong to  <XiaoMaGuo Technologies > own
* Description:  <description>
* Modify By :  XiaoMaGuo ^_^
* Modify Date:   2013-10-21
* Follow Order No.:  <Follow Order No.>
* Modify Order No.:  <Modify Order No.>
* Modify Content:  <modify content >
*/
package com.xiaoma.threadpooltest;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ProgressBar;
import android.widget.Toast;
/**
* @TODO [線程池控制 ]
* @author XiaoMaGuo ^_^
* @version [version-code, 2013-10-22]
* @since [Product/module]
*/
public class MyRunnableActivity extends Activity implements OnClickListener
{
/** 任務執行隊列 */
private ConcurrentLinkedQueue<MyRunnable> taskQueue = null;
/**
* 正在等待執行或已經完成的任務隊列
*
* 備註:Future類,一個用於存儲異步任務執行的結果,好比:判斷是否取消、是否能夠取消、是否正在執行、是否已經完成等
*
* */
private ConcurrentMap<Future, MyRunnable> taskMap = null;
/**
* 建立一個不限制大小的線程池 此類主要有如下好處 1,以共享的無界隊列方式來運行這些線程. 2,執行效率高。 3,在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態
* 4,若是在關閉前的執行期間因爲失敗而致使任何線程終止,那麼一個新線程將代替它執行後續的任務(若是須要)。
*
* */
private ExecutorService mES = null;
/** 在此類中使用同步鎖時使用以下lock對象便可,官方推薦的,不推薦直接使用MyRunnableActivity.this類型的,能夠詳細讀一下/framework/app下面的隨便一個項目 */
private Object lock = new Object();
/** 喚醒標誌,是否喚醒線程池工做 */
private boolean isNotify = true;
/** 線程池是否處於運行狀態(即:是否被釋放!) */
private boolean isRuning = true;
/** 任務進度 */
private ProgressBar pb = null;
/** 用此Handler來更新咱們的UI */
private Handler mHandler = null;
/**
* Overriding methods
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.my_runnable_main);
init();
}
public void init()
{
pb = (ProgressBar)findViewById(R.id.progressBar1);
findViewById(R.id.button1).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
findViewById(R.id.button3).setOnClickListener(this);
findViewById(R.id.button4).setOnClickListener(this);
findViewById(R.id.button5).setOnClickListener(this);
taskQueue = new ConcurrentLinkedQueue<MyRunnable>();
taskMap = new ConcurrentHashMap<Future, MyRunnable>();
if (mES == null)
{
mES = Executors.newCachedThreadPool();
相關文章
相關標籤/搜索