今天要讲的东西就是线程池、线程的高效率使用,灵活控制!今天就用最常用的几种方式来分别实现应用中使用的线程方面的知识,(共写了两个不同入口的Activity来分开不同的实现方式,大家可以自行注释AndroidManifest.xml中的Launch入口或打开注释)任何发代码中的具体实现效果,好了,先随便列几个吧,如:AsyncTask、Runnable、Thread、ThreadPool、Executors等等的使用,看我文章的朋友应该都很清楚小马的方式啦,果断先上效果,再一步步分解代码。
源码下载地址:http://download.csdn.net/detail/jdsjlzx/8454373
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);
}
}
<?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>
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();
}
// 用于更新ProgressBar进度条
mHandler = new Handler()
{
/**
* Overriding methods
*
* @param msg
*/
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
pb.setProgress(msg.what);
}
};
}
/**
* Overriding methods
*
* @param v
*/
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.button1:
start();
break;
case R.id.button2:
stop();
break;
case R.id.button3:
reload(new MyRunnable(mHandler));
break;
case R.id.button4:
release();
break;
case R.id.button5:
addTask(new MyRunnable(mHandler));
break;
default:
break;
}
}
/**
* <Summary Description>
*/
private void addTask(final MyRunnable mr)
{
mHandler.sendEmptyMessage(0);
if (mES == null)
{
mES = Executors.newCachedThreadPool();
notifyWork();
}
if (taskQueue == null)
{
taskQueue = new ConcurrentLinkedQueue<MyRunnable>();
}
if (taskMap == null)
{
taskMap = new ConcurrentHashMap<Future, MyRunnable>();
}
mES.execute(new Runnable()
{
@Override
public void run()
{
/**
* 插入一个Runnable到任务队列中 这个地方解释一下,offer跟add方法,试了下,效果都一样,没区别,官方的解释如下: 1 offer : Inserts the specified
* element at the tail of this queue. As the queue is unbounded, this method will never return
* {@code false}. 2 add: Inserts the specified element at the tail of this queue. As the queue is
* unbounded, this method will never throw {@link IllegalStateException} or return {@code false}.
*
*
* */
taskQueue.offer(mr);
// taskQueue.add(mr);
notifyWork();
}
});
Toast.makeText(MyRunnableActivity.this, "已添加一个新任务到线程池中 !", 0).show();
}
/**
* <Summary Description>
*/
private void release()
{
Toast.makeText(MyRunnableActivity.this, "释放所有占用的资源!", 0).show();
/** 将ProgressBar进度置为0 */
mHandler.sendEmptyMessage(0);
isRuning = false;
Iterator iter = taskMap.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry<Future, MyRunnable> entry = (Map.Entry<Future, MyRunnable>)iter.next();
Future result = entry.getKey();
if (result == null)
{
continue;
}
result.cancel(true);
taskMap.remove(result);
}
if (null != mES)
{
mES.shutdown();
}
mES = null;
taskMap = null;
taskQueue = null;
}
/**
* <Summary Description>
*/
private void reload(final MyRunnable mr)
{
mHandler.sendEmptyMessage(0);
if (mES == null)
{
mES = Executors.newCachedThreadPool();
notifyWork();
}
if (taskQueue == null)
{
taskQueue = new ConcurrentLinkedQueue<MyRunnable>();
}
if (taskMap == null)
{
taskMap = new ConcurrentHashMap<Future, MyRunnable>();
}
mES.execute(new Runnable()
{
@Override
public void run()
{
/** 插入一个Runnable到任务队列中 */
taskQueue.offer(mr);
// taskQueue.add(mr);
notifyWork();
}
});
mES.execute(new Runnable()
{
@Override
public void run()
{
if (isRuning)
{
MyRunnable myRunnable = null;
synchronized (lock)
{
myRunnable = taskQueue.poll(); // 从线程队列中取出一个Runnable对象来执行,如果此队列为空,则调用poll()方法会返回null
if (myRunnable == null)
{
isNotify = true;
}
}
if (myRunnable != null)
{
taskMap.put(mES.submit(myRunnable), myRunnable);
}
}
}
});
}
/**
* <Summary Description>
*/
private void stop()
{
Toast.makeText(MyRunnableActivity.this, "任务已被取消!", 0).show();
for (MyRunnable runnable : taskMap.values())
{
runnable.setCancleTaskUnit(true);
}
}
/**
* <Summary Description>
*/
private void start()
{
if (mES == null || taskQueue == null || taskMap == null)
{
Log.i("KKK", "某资源是不是已经被释放了?");
return;
}
mES.execute(new Runnable()
{
@Override
public void run()
{
if (isRuning)
{
MyRunnable myRunnable = null;
synchronized (lock)
{
myRunnable = taskQueue.poll(); // 从线程队列中取出一个Runnable对象来执行,如果此队列为空,则调用poll()方法会返回null
if (myRunnable == null)
{
isNotify = true;
// try
// {
// myRunnable.wait(500);
// }
// catch (InterruptedException e)
// {
// e.printStackTrace();
// }
}
}
if (myRunnable != null)
{
taskMap.put(mES.submit(myRunnable), myRunnable);
}
}
}
});
}
private void notifyWork()
{
synchronized (lock)
{
if (isNotify)
{
lock.notifyAll();
isNotify = !isNotify;
}
}
}
}
package com.xiaoma.threadpooltest;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
/**
* @TODO [The Class File Description]
* @author XiaoMaGuo ^_^
* @version [version-code, 2013-10-21]
* @since [Product/module]
*/
public class MyRunnable implements Runnable
{
private boolean cancleTask = false;
private boolean cancleException = false;
private Handler mHandler = null;
public MyRunnable(Handler handler)
{
mHandler = handler;
}
/**
* Overriding methods
*/
@Override
public void run()
{
Log.i("KKK", "MyRunnable run() is executed!!! ");
runBefore();
if (cancleTask == false)
{
running();
Log.i("KKK", "调用MyRunnable run()方法");
}
runAfter();
}
/**
* <Summary Description>
*/
private void runAfter()
{
Log.i("KKK", "runAfter()");
}
/**
* <Summary Description>
*/
private void running()
{
Log.i("KKK", "running()");
try
{
// 做点有可能会出异常的事情!!!
int prog = 0;
if (cancleTask == false && cancleException == false)
{
while (prog < 101)
{
if ((prog > 0 || prog == 0) && prog < 70)
{
SystemClock.sleep(100);
}
else
{
SystemClock.sleep(300);
}
if (cancleTask == false)
{
mHandler.sendEmptyMessage(prog++);
Log.i("KKK", "调用 prog++ = " + (prog));
}
}
}
}
catch (Exception e)
{
cancleException = true;
}
}
/**
* <Summary Description>
*/
private void runBefore()
{
// TODO Auto-generated method stub
Log.i("KKK", "runBefore()");
}
public void setCancleTaskUnit(boolean cancleTask)
{
this.cancleTask = cancleTask;
Log.i("KKK", "点击了取消任务按钮 !!!");
// mHandler.sendEmptyMessage(0);
}
}
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
|
<?
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:orientation
=
"vertical"
>
<
LinearLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:orientation
=
"horizontal"
>
<
Button
android:id
=
"@+id/button5"
android:layout_width
=
"0dp"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"添加任务"
/>
<
Button
android:id
=
"@+id/button1"
android:layout_width
=
"0dp"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"开始任务"
/>
<
Button
android:id
=
"@+id/button2"
android:layout_width
=
"0dp"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"取消任务"
/>
<
Button
android:id
=
"@+id/button3"
android:layout_width
=
"0dp"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"重新加载"
/>
<
Button
android:id
=
"@+id/button4"
android:layout_width
=
"0dp"
android:layout_height
=
"wrap_content"
android:layout_weight
=
"1"
android:text
=
"释放资源"
/>
</
LinearLayout
>
<
include
layout
=
"@layout/my_runnable_merge"
/>
</
LinearLayout
>
|
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
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
xmlns:android
=
"http://schemas.android.com/apk/res/android"
package
=
"com.xiaoma.threadpooltest"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"8"
android:targetSdkVersion
=
"15"
/>
<
application
android:allowBackup
=
"true"
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
android:theme
=
"@style/AppTheme"
>
<
activity
android:name
=
"Main"
android:label
=
"@string/app_name"
>
<!-- <intent-filter> -->
<!-- <action android:name="android.intent.action.MAIN" /> -->
<!-- <category android:name="android.intent.category.LAUNCHER" /> -->
<!-- </intent-filter> -->
</
activity
>
<
activity
android:name
=
"MyRunnableActivity"
android:label
=
"@string/app_name"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
</
application
>
</
manifest
>
|