Android中有关线程Thread等相关知识的笔记
线程Thread
每个应用程序在创建时都会默认运行单一的进程,其中包含所有的任务。为避免用户界面被挂起,那些耗时的任务 ,诸如网络下载或密集的计算,应当驻留于单独的后台线程中,如何适当地实现这种操作由开发者决定,但之后则是由Android系统基于开发者的实现来确定线程的优先级。
大多数应用程序都通过使用线程来提升性能。如果用户界面的挂起在软件设计阶段没有被发觉,到了测试阶段就会迅速体现出来,因为Android系统会在用户界面挂起时弹出警告—告诉用户Slow app isn’t responding.
Android Thread的使用方法:
Thread的使用方法主要有两种方法:其中一种是extends Thread,然后重载Thread的run()函数,另一种是构建一个新的Thread对象,可带Runnable或不带。但不管怎么样,都是要通过start()函数来运行相应的代码
构建Thread对象的方法如下:
1、Thread()不代任何参数,该方法会在构建的时候自动生成线程名字。
举例:
Thread mThread = new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread_test");
super.run();
}
};
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:22:08.692: INFO/System.out(831): Thread-10
04-27 09:22:08.702: INFO/System.out(831): This is thread_test
2、Thread(Runnable runnable)该函数多了Runnable个对象,被运行的代码在Runnable对象里。
举例:
Runnable mRunnable = new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread with Runnable");
}
};
Thread mThread = new Thread(mRunnable);
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:37:47.832: INFO/System.out(865): Thread-11
04-27 09:37:47.861: INFO/System.out(865): This is thread with Runnable
3、Thread(Runnable runnable,String threadName)该函数有Runnable也有自己的名字threadName。
举例:
Runnable mRunnable = new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is thread with Runnable and Name");
}
};
Thread mThread = new Thread(mRunnable,"mThreadTest");
mThread.start();
System.out.println(mThread.getName());
得到的logcat:
04-27 09:44:03.682: INFO/System.out(900): mThreadTest
04-27 09:44:03.702: INFO/System.out(900): This is thread with Runnable and Name
Runable和Thread的关系
在java中可有两种方法实现多线程,一种是继承Thread类,一种是实现Runnable接口;
1)继承Thread类的方式
Thread类是在java.lang包中定义的 。一个类只要继承了Thread类同时覆写了本类中的run()
步骤就可以实现多线程操作了,然而一个类只能继承一个父类,这是此种方法的的局限 。 下面看例子:
class MyThread extends Thread{
private String name;
public MyThread(String name) {
super();
this.name = name;
}
public void run() {
for(int i=0;i<10;i++) {
System.out.println("线程开端:"+this.name+",i="+i);
}
}
}
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1=new MyThread("线程a");
MyThread mt2=new MyThread("线程b");
mt1.start();
mt2.start();
}
}
2) Runnable接口
在实际开辟中一个多线程的操作很少 使用Thread类,而是通过Runnable接口实现 。 public interface Runnable{ public void run(); }
例子:
class MyThread implements Runnable{
private String name;
public MyThread(String name) {
this.name = name;
}
public void run(){
for(int i=0;i<100;i++){
System.out.println("线程开端:"+this.name+",i="+i);
}
}
};
然而在Runnable的子类中没有start() 方法,只有Thread类中才有 。此时视察Thread类,有一个构造函数:public Thread(Runnable targer) 此构造函数接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现多线程 。(start() 可以协调系统的资源):
public class ThreadDemo01 {
public static void main(String[] args) {
MyThread mt1=new MyThread("线程a");
MyThread mt2=new MyThread("线程b");
new Thread(mt1).start();
new Thread(mt2).start();
}
}
3)实际中如何应用这两种实现模式
在程序实现多线程应优先以实现Runnable接口为主,由于实现Runnable接口相比继承Thread类有如下好处:
1.避免点继承的局限,一个类可以继承多个接口 。
2. 利于资源的共享。
以卖票程序为例,通过Thread类实现:
class MyThread extends Thread {
private int ticket=10;
public void run(){
for(int i=0;i<20;i++) {
if(this.ticket>0){
System.out.println("卖票:ticket"+this.ticket--);
}
}
}
};
下面通过三个线程对象,同时卖票:
public class ThreadTicket {
public static void main(String[] args) {
MyThread mt1=new MyThread();
MyThread mt2=new MyThread();
MyThread mt3=new MyThread();
mt1.start();//每个线程都各卖了10张,共卖了30张票
mt2.start();//但实际只有10张票,每个线程都卖自己的票
mt3.start();//没有达到资源共享
}
}
假如用Runnable就 可以实现资源共享,下面看例子:
class MyThread implements Runnable{
private int ticket=10;
public void run(){
for(int i=0;i<20;i++){
if(this.ticket>0){
System.out.println("卖票:ticket"+this.ticket--);
}
}
}
}
public class RunnableTicket {
public static void main(String[] args) {
MyThread mt=new MyThread();
new Thread(mt).start();//同一个mt
new Thread(mt).start();
new Thread(mt).start();
}
};
现在程序中有三个线程,然而一共卖了10张票,也就是说使用Runnable实现多线程可以达到资源共享的目的。
4)Runnable接口和Thread的关系总结
(1) 说白了就是类和接口的区别。Thread是一个类,java中是不允许继承多个父类的,这就是Thread的一个局限性。而使用Runnable就不同了,可以implements多个接口,同时继承一个父类,这样会更加灵活。
(2) 当多个线程需要共享资源时,用Thread很难达到目的,但是用Runnable接口就容易许多了。
(3) 二者的联系:看源码可以发现,Thread其实就是继承了Runnable接口的子类。
取消线程
有时,当一个组件完成或被杀死是,开发者希望有它产生的线程也同样被杀死,例如在某个Acitivity中定义了线程:
private …Thread myThread;
myThread.stop()方法已经被弃用了,因为它会将应用程序置于不可预知的状态,取而代之的是下面的方法,比如在父组件的onStop()方法中加入
if(myThread != null){
Thread dummy = myThread;
myThread = null;
dummy.interrupt();
}
在应用程序层面上还有另外一种方法来完成相同的工作:使用setDaemon(true)方法将所有生成的线程都声明为守护线程,可以确保所有与应用程序关联的线程在应用程序的主线程终结时,也随之被杀死。
//use when initially starting a thread
myThread。setDaemon(true);
myThread.start();
设置线程的优先级
Android系统会处理线程的优先级,默认情况下,一个新线程,如myThread,其优先级被定为5。开发者可以在myThread.start()执行之前,通过调用myThread.setPriority(priority)来为线程设定另外的优先级。优先级不能高于Thread.MAX_PRIORITY(10)或者低于Thread.MIN_PRIORITY(1)
Android还提供了另一种设定线程优先级的方法通过android.os.Process.setThreadPriority (int tid, int priority)
priority:【-20, 19】,高优先级 -> 低优先级。在实际操作中,因为setThreadPriority 是一个基于“良好的”Linux值得优先级,可以设定的粒度更细,并且对线程的影响也更加明显。