ThreadLocal, HandleThread, IntentService

1. ThreadLocal用法详解和原理https://www.cnblogs.com/coshaho/p/5127135.html

// ThreadLocal methods:

public T get() {}

public void set(T value) {}

public void remove() {}

protected T initialValue()

ThreadLocal.get()

ThreadLocal.set(T value)

ThreadLocal.remove()

ThreadLocal.initialValue()

 

package com.coshaho.reflect;

/**

* ThreadLocal用法

* @author coshaho

*

*/

public class MyThreadLocal {

private static final ThreadLocal threadLocal = new ThreadLocal() {

/**

* ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值

*/

@Override

protected Object initialValue() {

System.out.println("调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!");

return null;

}

};

public static void main(String[] args) {

new Thread(new MyIntegerTask("IntegerTask1")).start();

new Thread(new MyStringTask("StringTask1")).start();

new Thread(new MyIntegerTask("IntegerTask2")).start();

new Thread(new MyStringTask("StringTask2")).start();

}

public static class MyIntegerTask implements Runnable {

private String name;

MyIntegerTask(String name) {

this.name = name;

}

@Override

public void run() {

for(int i = 0; i < 5; i++) {

// ThreadLocal.get方法获取线程变量

if (null == MyThreadLocal.threadLocal.get()) {

// ThreadLocal.et方法设置线程变量

MyThreadLocal.threadLocal.set(0);

System.out.println("线程" + name + ": 0");

} else {

int num = (Integer)MyThreadLocal.threadLocal.get();

MyThreadLocal.threadLocal.set(num + 1);

System.out.println("线程" + name + ": " + MyThreadLocal.threadLocal.get());

if(i == 3) {

MyThreadLocal.threadLocal.remove();

}

}

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static class MyStringTask implements Runnable {

private String name;

MyStringTask(String name) {

this.name = name;

}

@Override

public void run() {

for(int i = 0; i < 5; i++) {

if(null == MyThreadLocal.threadLocal.get()) {

MyThreadLocal.threadLocal.set("a");

System.out.println("线程" + name + ": a");

} else

String str = (String)MyThreadLocal.threadLocal.get();

MyThreadLocal.threadLocal.set(str + "a");

System.out.println("线程" + name + ": " + MyThreadLocal.threadLocal.get());

} try {

Thread.sleep(800);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

2. HandlerThread用法详解和原理

HandlerThread的特点

HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。

开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。

但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。

对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。

HandlerThread

HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.

HandlerThread的常规用法

创建一个HandlerThread

mThread = new HandlerThread("handler_thread");

启动一个HandlerThread

mThread.start();

退出循环Looper是通过调用loop方法驱动着消息循环的进行: 从MessageQueue中阻塞式地取出一个消息,然后让Handler处理该消息,周而复始,loop方法是个死循环方法。

 【Android Handler、Loop 的简单使用】 介绍了子线程和子线程之间的通信。

package lib.com.myapplication;

import android.os.Bundle;

import android.os.Handler;

import android.os.Looper;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

private Handler handler1 ;

private Handler handler2 ;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new MyThread1().start();

new MyThread2().start();

}

class MyThread1 extends Thread {

@Override

public void run() {

super.run();

Looper.prepare();

handler1 = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

System.out.println( "threadName--" + Thread.currentThread().getName() + "messageWhat-"+ msg.what );

}

};

try {

sleep( 3000 );

} catch (InterruptedException e) {

e.printStackTrace();

}

handler2.sendEmptyMessage( 2 ) ;

Looper.loop();

}

}

class MyThread2 extends Thread {

@Override

public void run() {

super.run();

Looper.prepare();

handler2 = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

System.out.println( "threadName--" + Thread.currentThread().getName() + "messageWhat-"+ msg.what );

}

};

try {

sleep( 4000 );

} catch (InterruptedException e) {

e.printStackTrace();

}

handler1.sendEmptyMessage( 5 ) ;

Looper.loop();

}

}

}

 

很明显的一点就是,我们要在子线程中调用Looper.prepare() 为一个线程开启一个消息循环,默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 然后通过Looper.loop() 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

然而这一切都可以用HandlerThread类来帮我们做这些逻辑操作。

 

HandlerThreadDemo:

package com.app;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

public class MainActivity extends AppCompatActivity {

private HandlerThread myHandlerThread;

private Handler handler;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//创建一个线程,线程名字:handler-thread

myHandlerThread = new HandlerThread( "handler-thread");

//开启一个线程

myHandlerThread.start();

//在这个线程中创建一个handler对象

handler = new Handler( myHandlerThread.getLooper() ) {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作

Log.d( "handler " , "消息: " + msg.what + " 线程: " + Thread.currentThread().getName() );

}

};

//在主线程给handler发送消息

handler.sendEmptyMessage( 1 );

new Thread(new Runnable() {

@Override

public void run() {

//在子线程给handler发送数据

handler.sendEmptyMessage( 2 );

}

}).start();

}

@Override

protected void onDestroy() {

super.onDestroy();

//释放资源

myHandlerThread.quit();

}

}

 

3.IntentService用法详解和原理

https://www.cnblogs.com/denluoyia/p/5997452.html

IntentService是继承并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

HandlerThread thread = new HandlerThread()

 

定义一个IntentService的子类:

public class MIntentService extends IntentService {

public MIntentService(){

super("MIntentService");

}

/**

* Creates an IntentService. Invoked by your subclass's constructor.

* @param name Used to name the worker thread, important only for debugging.

*/

public MIntentService(String name) {

super(name);

}

@Override

public void onCreate() {

Log.e("MIntentService--", "onCreate");

super.onCreate();

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Log.e("MIntentService--", "onStartCommand");

return super.onStartCommand(intent, flags, startId);

}

@Override

protected void onHandleIntent(Intent intent) {

Log.e("MIntentService--", Thread.currentThread().getName() + "--" + intent.getStringExtra("info") );

for(int i = 0; i < 100; i++){ //耗时操作

Log.i("onHandleIntent--", i + "--" + Thread.currentThread().getName());

}

}

@Override

public void onDestroy() {

Log.e("MIntentService--", "onDestroy");

super.onDestroy();

}

}

开启IntentService服务:

public void intentClick(View v){

Intent intent = new Intent(this, MIntentService.class);

intent.putExtra("info", "good good study");

startService(intent);

}

 

Intent服务开启后,执行完onHandleIntent里面的任务就自动销毁结束,通过打印的线程名称可以发现是新开了一个线程来处理耗时操作的,即是耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。

 

查看原文

发表评论

返回顶部暗黑模式