1.线程通信基础
- 生成者消费者
2.AsyncTask
- FutureTask
- 线程池
- 问题和缺点
3.HandlerThread
- 优点
- 例子
- IntentService
- 原理和使用
- 优点
5.Loader
- 优点
- 例子
1.线程通信基础
1.1.普通的生产者消费者模式
public class ThreadTest1 {
//产品
static class ProductObject{
//线程操作变量可见
public volatile static String value;
}
//生产者线程
static class Producer extends Thread{
@Override
public void run() {
//不断生产产品
while(true){
if(ProductObject.value == null){
ProductObject.value = "NO:"+System.currentTimeMillis();
System.out.println("生产产品:"+ProductObject.value);
}
}
}
}
//消费者线程
static class Consumer extends Thread{
@Override
public void run() {
while(true){
if(ProductObject.value != null){
System.out.println("消费产品:"+ProductObject.value);
ProductObject.value = null;
}
}
}
}
public static void main(String[] args) {
new Producer().start();
new Consumer().start();
}
}
当两个线程对同一个值value操作的时候,在每个线程中都会有一个私有空间保存这个值,即每个线程分别有一个value,假如A线程修改了value,B是不知道A修改了。
1.boolean value=true
生成者线程中vaule修改为false,消费者中的value任然为true。
如何修改:给修改值加上volatile,就能保证同步。
volatile boolean value=true;
1.2.优化
但是volatile的这种操作也会带来一个问题,就是消费者和生产者线程需要不断的去判断值是否消费,这样也会带来性能消耗,这里引入了锁的概念。
public class ThreadTest1 {
//产品
static class ProductObject{
//线程操作变量可见
public volatile static String value;
}
//生产者线程
static class Producer extends Thread{
Object lock;
public Producer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
//不断生产产品
while(true){
synchronized (lock) { //互斥锁
//产品还没有被消费,等待
if(ProductObject.value != null){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//产品已经消费完成,生产新的产品
ProductObject.value = "NO:"+System.currentTimeMillis();
System.out.println("生产产品:"+ProductObject.value);
lock.notify(); //生产完成,通知消费者消费
}
}
}
}
//消费者线程
static class Consumer extends Thread{
Object lock;
public Consumer(Object lock) {
this.lock = lock;
}
@Override
public void run() {
while(true){
synchronized (lock) {
//没有产品可以消费
if(ProductObject.value == null){
//等待,阻塞
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费产品:"+ProductObject.value);
ProductObject.value = null;
lock.notify(); //消费完成,通知生产者,继续生产
}
}
}
}
public static void main(String[] args) {
Object lock = new Object();
new Producer(lock).start();
new Consumer(lock).start();
}
}
2.AsyncTask
Android的刷新频率是60fps,如果低于25fps,就会感觉有卡顿的现象。
优化点:减少主线程的负担,创建子线程进行处理。那么就涉及到子线程和主线程的通信。
子线程和主线程的通信方式:
- AsyncTask
- Handler
2.1.FutureTask
Callable:可以返回结果,Runable是无法获取结果的
Future
在普通的线程中(比如上面的例子),异步任务执行的结果,主线程是无法轻易获取。
FutureTask是可以获取到异步线程中的结果。
Java FutureTask 异步任务操作提供了便利性:
- 1.获取异步任务的返回值
- 2.监听异步任务的执行完毕
- 3.取消异步任务
public AsyncTask() {
// 实现了Callable
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams); //子线程
Binder.flushPendingCommands();
return postResult(result);
}
};
//实现了RunnableFuture
mFuture = new FutureTask(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get()); //主线程
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
FutureTask模式实现:
public class FutureTest1 {
public static void main(String[] args) {
Task work = new Task();
FutureTask future = new FutureTask(work){
//异步任务执行完成,回调
@Override
protected void done() {
try {
System.out.println("done:"+get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
//线程池(使用了预定义的配置)
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(future);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//取消异步任务
future.cancel(true);
try {
//阻塞,等待异步任务执行完毕
System.out.println(future.get()); //获取异步任务的返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//异步任务
static class Task implements Callable{
//返回异步任务的执行结果
@Override
public Integer call() throws Exception {
int i = 0;
for (; i < 10; i++) {
try {
System.out.println(Thread.currentThread().getName() + "_"+i);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i;
}
}
}
doBackground()在call方法中执行
call的返回值在Future的done方法中获取
->onPostExecute
new MyTask().execute();
2.2.执行流程:
->onPostExecute
new MyTask().execute();
实例化:
new AsyncTask() -> new FutureTask()
执行:
Executor.execute(mFuture) -> SerialExecutor.myTasks(队列)
-> (线程池)THREAD_POOL_EXECUTOR.execute
线程池中的所有线程,为了执行异步任务
2.3.线程池:
线程池中的所有线程,为了执行异步任务
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE,TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
参数 | 意义 |
---|---|
CORE_POOL_SIZE | 核心线程数 |
MAXIMUM_POOL_SIZE | 最大线程数量 |
KEEP_ALIVE | 1s闲置回收 |
TimeUnit.SECONDS | 时间单位 |
sPoolWorkQueue | 异步任务队列 |
sThreadFactory | 线程工厂 |
- 如果当前线程池中的数量小于corePoolSize,创建并添加的任务。
- 如果当前线程池中的数量等于corePoolSize,缓冲队列 workQueue未满,那么任务被放入缓冲队列、等待任务调度执行。
- 如果当前线程池中的数量大于corePoolSize,缓冲队列workQueue已满,并且线程池中的数量小于maximumPoolSize,新提交任务会创建新线程执行任务。
- 如果当前线程池中的数量大于corePoolSize,缓冲队列workQueue已满,并且线程池中的数量等于maximumPoolSize,新提交任务由Handler处理。
- 当线程池中的线程大于corePoolSize时,多余线程空闲时间超过keepAliveTime时,会关闭这部分线程。
最终AsyncTask执行的任务是在线程池中执行的,如果创建大量的线程,会出现线程堵塞的现象(FC的风险)。
2.4.问题和缺点:参考
- 1.生命周期;
- 2.内存泄漏;
- 3.结果丢失;
- 4.并行还是串行;
- 5.线程池不够导致抛出异常:线程池中已经有128个线程,缓冲队列已满,如果此时向线程提交任务,将会抛出RejectedExecutionException。过多的线程会引起大量消耗系统资源和导致应用FC的风险;
- 6.异步任务中只能干一件事情,一个线程只能干一件事情。
添加任务到线程池的过程是串行,在线程池中执行时是并行。
public class AsyncTaskTest {
public static void main(String[] args) {
int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //可用的CPU个数
int CORE_POOL_SIZE = CPU_COUNT + 1; //5
int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //9
int KEEP_ALIVE = 1;
//任务队列(128)
final BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
//线程工厂
ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
String name = "Thread #" + mCount.getAndIncrement();
System.out.println(name);
return new Thread(r, name);
}
};
//线程池
Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
//执行异步任务
//如果当前线程池中的数量大于corePoolSize,缓冲队列workQueue已满,
//并且线程池中的数量等于maximumPoolSize,新提交任务由Handler处理。
//RejectedExecutionException
for (int i = 0; i < 200; i++) {
//相当于new AsyncTask().execute();
THREAD_POOL_EXECUTOR.execute(new MyTask());
}
}
static class MyTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
/*while(true){
try {
System.out.println(Thread.currentThread().getName());
//Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}*/
}
}
}
AsyncTask可以自定义线程池,风险是:太多线程可能导致内存消耗太多。
//1.使用的默认线程池
task = new MyTask();
task.execute();
//2.线程池扩容,自定义线程池
Executor exec = Executors.newScheduledThreadPool(25);
for (int i = 0; i < 200; i++) {
new MyTask().executeOnExecutor(exec);
}
在Activity的onDestroy中task.cancel(true),并不能真正取消线程执行。
AsyncTask的handler用到的的Looper是主线程的,如果任务太多,在主线程中进行轮询,会导致UI线程有卡顿的现象。
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult> result = (AsyncTaskResult>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
3.HandlerThread
那如果对异步任务的轮询放在子线程中处理,会不会好点呢。那么就引出了HandlerThread,他就是一个Thread
public class HandlerThreadActivity1 extends Activity {
HandlerThread fetchThread = new HandlerThread("fetching_thread");
Handler fetchHandler;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
tv = (TextView) findViewById(R.id.tv);
//启动线程
fetchThread.start();
//通过fetchHandler发送的消息,会被fetchThread线程创建的轮询器拉取到
fetchHandler = new Handler(fetchThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//模拟访问网络延迟
SystemClock.sleep(1000);
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("泰铢汇率:"+new Random().nextInt(10));
}
});
//循环执行
fetchHandler.sendEmptyMessage(1);
}
};
}
@Override
protected void onResume() {
super.onResume();
fetchHandler.sendEmptyMessage(1);
}
@Override
protected void onStop() {
super.onStop();
fetchThread.quit(); //取消
}
}
3.1.HandlerThread的优点:
- 1.减轻主线程的压力,提高UI的流畅度(减少主线程的轮询);
- 2.可以处理多个任务,开启一个线程起到多个线程的作用(原理是:looper共享)
3.2.例子
1.打开相机
2.预览回调(编码)
public class HandlerThreadActivity2 extends Activity implements Callback {
static final String TAG = "jason";
Camera mCamera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
byte[] buffers;
HandlerThread mHandlerThread = new HandlerThread("my_handlerthread");
Handler subHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread2);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
class MyTask implements Runnable, PreviewCallback{
@Override
public void run() {
//打开相机
//子线程中打开
Log.d("jason", Thread.currentThread().getName() + "_open");
mCamera = Camera.open(CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
//设置相机参数
parameters.setPreviewSize(480, 320); //预览画面宽高
mCamera.setParameters(parameters);
//获取预览图像数据
buffers = new byte[480 * 320 * 4];
mCamera.addCallbackBuffer(buffers);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
Log.d(TAG, Thread.currentThread().getName()+ "_run");
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if(mCamera != null){
mCamera.addCallbackBuffer(buffers);
//编码
Log.d(TAG, Thread.currentThread().getName()+ "_onPreviewFrame");
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mHandlerThread.start();
subHandler = new Handler(mHandlerThread.getLooper());
subHandler.post(new MyTask());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
如果用AsyncTask,onPreviewFrame的执行就到了主线程。为什么呢?
相机中的代码Camera:
异步任务的Looper,使用的MainLooper
Handler.handleMessage的执行,一定在它的Looper线程中
onPreviewFrame的执行,在Camera所持有的Looper线程中执行
new Camera -> looper -> EventHandler.handleMessage -> onPreviewFrame
private int cameraInitVersion(int cameraId, int halVersion) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
return native_setup(new WeakReference(this), cameraId, halVersion,
ActivityThread.currentOpPackageName());
}
java中普通的线程其他方法调用执行情况:
public class ThreadTest2 {
static class MyTask extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "_run");
}
void onPreviewFrame(){
System.out.println(Thread.currentThread().getName() + "_onPreviewFrame");
}
}
public static void main(String[] args) {
//子线程
MyTask task = new MyTask();
task.start();
//在主线程执行
task.onPreviewFrame();
}
}
4.IntentService
4.1.原理和使用
IntentService(本质:Service+HandlerThread+Intent)
要通过startService来启动,bindService没什么用;
public class IntentServiceActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
}
//发送意图给IntentService,启动子线程执行任务
public void mClick(View btn){
Intent intent = new Intent(this,MyIntentService.class);
startService(intent);
}
}
public class MyIntentService extends IntentService {
//至少要有一个空的构造方法
public MyIntentService() {
super("MyIntentService");
}
public MyIntentService(String name) {
super(name);
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d("jason", Thread.currentThread().getName() + "_onStart");
}
//UI线程发送Intent,会在子线程中执行
@Override
protected void onHandleIntent(Intent intent) {
Log.d("jason", Thread.currentThread().getName() + "_onHandleIntent");
}
}
至少要有一个空的构造方法
4.2.优点
- 1.提高子线程的优先级
- 2.减轻主线程的压力
IntentService内部会创建一个HandlerThread,onHandleIntent在HandlerThread线程中执行
5.Loader
Activity中启动子线程存在的问题:
- 1.内存泄露
- 2.无效的更新UI
Loader保证子线程与Activity或者Fragment的生命周期一致
Activity和Fragment自带LoaderManager
5.1.优点:
1.方便
2.Activity或者Fragment的生命周期一致
3.数据缓存与更新通知
5.2.例子:
查询通话记录,是一个比较耗时的操作,应该放在子线程中处理。
优点:
1.数据查询和跟新UI不需要自己去做线程切换和处理;
2.数据更新后,自动更新;
3.Activity销毁后,自动取消查询数据库操作。
使用加载器加载通话记录:
public class MainActivity extends Activity {
private static final String TAG = "jason";
// 查询指定的条目
private static final String[] CALLLOG_PROJECTION = new String[] { CallLog.Calls._ID, CallLog.Calls.NUMBER,
CallLog.Calls.CACHED_NAME, CallLog.Calls.TYPE, CallLog.Calls.DATE };
private ListView mListView;
private MyLoaderCallback mLoaderCallback = new MyLoaderCallback();
private MyCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.lv_list);
mAdapter = new MyCursorAdapter(MainActivity.this, null);
mListView.setAdapter(mAdapter);
//执行Loader的回调
getLoaderManager().initLoader(0, null, mLoaderCallback);
}
private class MyLoaderCallback implements LoaderManager.LoaderCallbacks {
//创建Loader
@Override
public Loader onCreateLoader(int id, Bundle args) {
//加载的过程在子线程中进行
CursorLoader loader = new CursorLoader(MainActivity.this, CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION,
null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
Log.d(TAG, "onCreateLoader");
return loader;
}
//Loader检测底层数据,当检测到改变时,自动执行新的载入获取最新数据
//Activity/Fragment所需要做的就是初始化Loader,并且对任何反馈回来的数据进行响应。
@Override
public void onLoadFinished(Loader loader, Cursor data) {
if (data == null)
return;
mAdapter.swapCursor(data);
Log.d(TAG, "onLoadFinished data count = " + data.getCount());
}
//OnDestroy,自动停止load
@Override
public void onLoaderReset(Loader loader) {
Log.d(TAG, "onLoaderReset");
mAdapter.swapCursor(null);
}
}
}