java 线程优化_多线程优化

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;

15011b618c59

image.png

1.2.优化

但是volatile的这种操作也会带来一个问题,就是消费者和生产者线程需要不断的去判断值是否消费,这样也会带来性能消耗,这里引入了锁的概念。

15011b618c59

image.png

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时,会关闭这部分线程。

15011b618c59

image.png

最终AsyncTask执行的任务是在线程池中执行的,如果创建大量的线程,会出现线程堵塞的现象(FC的风险)。

2.4.问题和缺点:参考

1.生命周期;

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);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值