Android 中的线程应用
1.Android 线程应用基础(Thread,Runnable)
2.Android 中的消息模型(Message,MessageQueue,Handler,Looper)
3.Android 中的异步任务(AsyncTask)
4.Android 中线程池的应用(Executor,ExecutorService
一.Android 线程应用基础
1.何为线程(Thread)?
线程是进程中的一个顺序的执行流,在Java中表现形式为Thread类型的对象。
进程:正在运行的一个程序,有自己独立的内存空间,可以启动多个线程并发执行。在一个多任务操作系统中允许多个进程并发执行。
说明:真正的并发是要构建于过个处理器的基础之上的。
2.多线程的优势,劣势?
1)优势:可以提高系统的并发处理能力,改善用户体验。
2)劣势:可能会导致线程安全问题。
3.Java 中线程对象的创建及应用?
Java 中线程的类型为Thread类型,我们可以通过此类型构建线程对象,并调用对象的start方法启动线程,线程启动以后会执行Thread类的run方法,我们可以将自己要执行的任务写在run方法中。
构建线程对象时,常用的构造方法:
1)Thread();
2)Thread(Runnable r);
4.线程状态及相关方法应用?
线程状态:
1.新建状态: new Thread()
2.就绪状态: start()
3.运行状态: run()
4.阻塞状态: sleep(3000),i/o阻塞
5.死亡状态: run()方法执行结束
线程方法:
1)start
3)sleep
4)setName (设置线程名字)
5)setPriority (设置优先级)
6)currentThread():获得当前线程
7)getName()....
8)setDaemon(true) 设置线程为守护线程
9)............
5.线程的同步?(重点,难点)
线程同步指多个线程在共享数据集上的互斥,协作(通讯)。同步的目的是为了保证数据的安全,让数据更符合我们的业务要求。
互斥的实现方式:
1)同步代码块synchronized(对象锁){被锁的内容}
2)同步方法(静态,非静态)
synchronized static void method(){} 对象锁为类对象
synchronized void method(){} 对象锁为this
说明:
1)加锁以后会影响系统的执行效率
2)在保证数据安全的情况下,锁的范围越小越好。
协作的实现方式:(保证业务的合理性)协作是构建在互斥的基础之上,然后借助Object对象的wait,notifiy,notifyall方法实现线程之间的通讯。
1)wait:等待(阻塞当前线程,并释放对象锁)
2)notifiy/notifyall:通知具备相同锁的对象开始执行。
说明:
1)wait,notifiy,notifyall必须用于同步代码块或同步方法内部
2)wait,notifiy,notifyall需要由对象锁调用。
demo 普通线程的创建及使用
//普通线程创建及使用(不考虑线程同步)
/**运行在主线程*/
public static void main(String[] args) {
//在主线程创建工作线程
thread th= new Thread(){
//工作线程
public void run() {
method01();
};
};
//t.setDaemon(true);
//设置线程为守护线程(如果需要设置守护线程 需要设置在线程启动之前)
th.start();//启动线程(处于就绪状态)
new Thread(new Runnable() {//target
@Override
public void run() {
method02();//此方法要运行在另一个工作线程
}
}).start(); //thread.run-->target.run
//在主线程执行method03
method03();
}
线程的同步之互斥
例子:多线程下的单例模式
class Singleton01{
private Singleton01(){}
private static Singleton01 instance;
//同步锁(锁可以是唯一的任意对象)
final static String LOCK="LOCK";//第一种写法 同步代码块
public static Singleton01 getInstance() {
synchronized (Singleton01.class) {
//同步代码块
if(instance==null){
instance=new Singleton01();
}
return instance;
}
//线程在执行此代码块时会获得锁,执行完以后释放锁。
}
/**第二种写法:同步方法
* 1)静态方法默认使用类对象作为对象锁
* 2)非静态方法默认使用this作为对象锁
* */
public synchronized static Singleton01 getInstance() {
if(instance==null){
instance=new Singleton01();
}
return instance;
}
//第三种写法:双重验证同步 (更高效)
public static Singleton01 getInstance() {
if(instance==null){
synchronized (Singleton01.class) {
//同步代码块
if(instance==null){
instance=new Singleton01();
}
}
}
return instance;
//线程在执行此代码块时会获得锁,执行完以后释放锁。
}
}
public class ThreadDemo03 {
static class Task implements Runnable{
@Override
public void run() {
System.out.println(
Singleton01.getInstance());
}
}
public static void main(String[] args) {
Task task=new Task();
new Thread(task).start();
new Thread(task).start();
new Thread(task).start();
new Thread(task).start();
}
**线程同步之线程协作
生产者与消费者模型DEMO**
/** 容器对象 */
class Container {
public Object[] datas;
/** 通过此变量记录有效元素个数 */
private int size;
public Container(int cap) {
this.datas = new Object[cap];
}
/** 此方法用于向容器放数据:要求满了则等待 */
public synchronized void put(Object data) {
// this
// 1.判定容器是否已满,满了则等待
if (datas.length == size)
try {
this.wait();
} catch (Exception e) {
}
// throw new RuntimeException("容器已满!");
// 2.容器不满则继续放数据
datas[size++] = data;
// 3.通知消费者(具备相同锁)可以取数据
this.notifyAll();
}
/** 此方法用于从容器取数据:要求空了则等待 */
public synchronized Object take() {
// this为对象锁
// 1.判定容器是否为空,空则等待
if (size == 0)
try {
this.wait();
} catch (Exception e) {
}
// throw new RuntimeException("容器没有数据!");
// 2.取数据
Object temp = datas[0];
// 3.数组往前移(数组长度减1)
System.arraycopy(datas, 1, datas, 0, size - 1);
size--;
datas[size] = null;
// 3.通知生产者(具备相同锁对象)可以继续放数据
this.notifyAll();
return temp;
}
}
/** 生产者对象:向容器放数据 */
class Producer extends Thread {
private Container container;
public Producer(Container container) {
this.container = container;
}
/** 生产者可以不断的放数据 */
@Override
public void run() {
int num = 0;
while (true) {
num++;
System.out.println("producer.put=" + num);
container.put(num);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
/** 消费者对象:从容器取数据 */
class Consumer extends Thread {
private Container container;
public Consumer(Container container) {
this.container = container;
}
@Override
public void run() {
while (true) {
Object data = container.take();
System.out.println("consumer.take=" + data);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}
public class ThreadCommuniation01 {
public static void main(String[] args) {
// 构建容器对象 Container c=new
// Container(5);
//BlockingQueue<Object> q=new
// ArrayBlockingQueue<>(5);
//构建生产者对象 Producer pro=new
// Producer(c); //构建消费者对象
// Consumer con=new Consumer(c);
// //启动线程 pro.start();
// con.start(); }}
}
二.Android 中的消息模型(Message,MessageQueue,Handler,Looper)
为什么要使用消息模型
使用Android中消息模型的目的是尽量不要去阻塞主线程,然后给用户一种比较友好的体验。
1.Android 中消息模型关注对象:
Message :数据的载体
MessageQueue: 存储多个消息对象
Looper:迭代消息队列,取出消息。
Handler:发送,处理消息队列中的消息。
2.Android 中消息模型应用案例?
1.工作线程发消息给主线程?
2.主线程发消息给主线程?
3.主线程发消息给工作线程?
3.记住:
1)主线程在启动时已经默认创建了Looper和消息队列对象
2)给谁发消息就让handler关联谁的Looper.
3)handler的handleMessage方法运行在哪个线程由handler关联的looper而定。
4.Android 中消息模型对象相关方法总结
1)Message(obj,what,obtain(),….)
2)MessageQueue
3)Looper(prepare(),myLooper(),loop(),getMainLooper(),quit())
4)Handler(sendMessage,handleMessage,sendXXXXX)
demo
工作线程发消息给主线程
public class MainActivity extends Activity {
private Handler mHandler;
/** onCreate方法运行在主线程 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 构建一个Handler,关联主线程的Looper
// 主线程在启动时会创建一个Looper,并关联一个消息对象
// 默认关联当前线程looper
// 主线程创建时默认创建一个looper,不需要再次创建(除了主线程都需要创建looper)
// mHandler=new Handler(){
mHandler = new Handler(Looper.getMainLooper()) {
// 当handler关联的looper所在线程收到消息以后会回调此方法
// 在此方法中可以执行消息的处理操作
// 此方法运行在哪个线程取决于handler关联的looper
// 一个线程最多有一个Looper对象
public void handleMessage(Message msg) {
if (msg.what == 1) {
// what表示做什么
isExit = false;
return;
}
setTitle((String) msg.obj);
};
};
}
public void onClick01(View v){
new Thread(){
@Override
public void run() {
try{sleep(5000);}catch(Exception e){}
//要发送的数据
String s="helloworld01";
//将如上数据交给主线程
//1.构建消息对象
Message msg=new Message();
//赋值
msg.obj=s;
//2.将消息对象发送给主线程
//记住:消息发送给谁,取决于handler关联的looper
mHandler.sendMessage(msg);
}
}.start();
}
boolean isExit;
/**点击回退操作3秒内重复点击退出 否则无效的方法*/
@Override
public void onBackPressed() {
if(!isExit){
Toast.makeText(this, "再点一次则退出",1).show();
isExit=true;
//第一种写法,线程等待3秒
/*new Thread(){
* public void run() {
* try{sleep(5000);}catch(Exception e){}
* isExit=false;
* };
* }.start();*/
//第二种写法,直接在工作线程创建handler延迟发送消息
/*new Handler(Looper.getMainLooper()){
* public void handleMessage(Message msg) {
* isExit=false;
* };
* }.sendEmptyMessageDelayed(1, 3000);
* *///向主线程发送带有what参数的延迟消息
mHandler.sendEmptyMessageDelayed(1,3000);
}else{
finish();
}
}
}
主线程向工作线程发消息
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private Looper wLooper;
//在此方法中发消息给工作线程
public void onClick(View v){
//构建工作线程
new Thread(){public void run(){
//创建一个looper,并绑定到当前线程
Looper.prepare();
//获得当前线程Looper
synchronized (MainActivity.this) {
wLooper=Looper.myLooper();
MainActivity.this.notify();
}
//迭代消息队列
Looper.loop();
}}.start();
synchronized (this) {
if(wLooper==null)
try{
this.wait();
}catch(Exception e){
}
}
//构建handler对象
//此方法运行在工作线程中 此方法运行在哪个线程 取决于绑定了哪个线程的looper (需要解决同步问题)
Handler h=new Handler(wLooper){
public void handleMessage(Message msg) {
String tname=Thread.currentThread().getName();
Log.i("TAG", tname+"-->"+msg.obj.toString());
};
};
//发送消息
Message msg=Message.obtain();
//获得一个消息
msg.obj="hello work thread";
h.sendMessage(msg);
}
}
主线程给主线程发送消息
public void onClick(View v){
Handler h = new Handler(
Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
Log.i("TAG",""+msg.obj);
}
};
Message msg =new Message();
msg.obj="hello";
//第一种 可以在主线程里面执行 sendMessage方法
// h.sendMessage(msg);
//第二种 执行post方法 post方法在线程执行
h.post(new Runnable() {
@Override
public void run() {
Log.i("TAG","run()");
}
});
}