文章目录
Android常用的多线程实现方法
说起多线程编程大家都不陌生,所谓线程就是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在Android开发中,当我们执行一些耗时操作,比如发起一条网络请求时,我们不知道服务器何时会响应请求,这类操作需要放在新的线程执行,以免阻塞主线程(UI线程)。在Android开发中常用的实现多线程的方式有以下几种:
1.Java原生的实现
作为Android开发常用的语言,Java已经为我们提供了多线程的实现,主要有以下三种方式:
1.继承Thread类,重写run方法;
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target;
3.通过Callable和FutureTask创建线程;
继承Thread类与实现Runnable接口的区别
那么这三种方法也是各有特点,实现Runnable接口方法相比于继承Thread类就有这几个优势:
1)由于Java不支持多继承,因此继承Thread类之后就不可以再继承别的类了,而实现Runnable接口方法可以解决单继承而带来的局限性;
2)增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
3)适合多个相同程序代码的线程去处理同一资源的情况
4)线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类
针对2)和3)这两点,我们以卖票系统举个例子,通过继承Thread类方式实现多线程如下:
public class MutliThreadDemo {
public static void main(String[] args) {
MutliThread m1=new MutliThread("Window 1");
MutliThread m2=new MutliThread("Window 2");
MutliThread m3=new MutliThread("Window 3");
m1.start();
m2.start();
m3.start();
}
}
public class MutliThread extends Thread {
private int ticket=100;//每个线程都拥有100张票
public MutliThread (){}
public MutliThread (String name){
super(name);
}
@Override
public void run() {
while(ticket>0){
System.out.println(ticket--+" is saled by "+Thread.currentThread().getName());
}
}
}
从结果可以看到,每个线程分别对应100张电影票,之间并无任何关系,这就说明每个线程之间是平等的,系统会分别为其分配内存资源。而如果我们要实现资源共享,也就是说这些线程卖同一份票池,使用这种方法就无法实现了,而使用Runnable接口方式就可以解决这个问题:
public class MutliThreadDemo {
public static void main(String[] args) {
MutliThread m=new MutliThread();
Thread t1=new Thread(m);
Thread t2=new Thread(m);
Thread t3=new Thread(m);
t1.start();
t2.start();
t3.start();
}
}
public class MutliThread implements Runnable{
private int ticket=100;//每个线程都拥有100张票
public void run(){
while(ticket>0){
System.out.println(ticket--+" is saled by "+Thread.currentThread());
}
}
}
如上所示,程序在内存中仅创建了一份资源,而新建的三个线程都是访问同一资源的。
在第一种方法中中,要想开多个线程,就要先new多个自定义类MutliThread对象,每一个自定义类MyThread的对象的成员变量都相同,这样需要在栈中开辟很多内存;
在第二种方法中中,要想开多个线程,只需要new一个自定义类MutliThread的对象,再new多个Thread类的对象即可,这样就大大节约了内存。
因此,我们说Runnable接口方式相比于继承Thread类方式,适合多个相同程序的代码去处理同一个资源的情况,能够把线程同程序的代码和数据有效分离(即耦合性降低),较好的体现了Java面向对象的设计思想。
实现Runnable接口与实现Callable接口的区别
实现Runnable接口和实现Callable接口的区别主要有以下几点:
1)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
2)实现Callable接口的任务线程能返回执行结果(需要调用FutureTask.get()方法实现,但会阻塞主线程直到获取返回结果),而实现Runnable接口的任务线程不能返回结果
3)Callable接口的call()方法允许抛出异常,而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛
4)加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法
我们看到相比于Runnable接口方法,Callable接口可以返回执行结果。因此如果你希望任务在完成的能返回一个值,那么可以通过Callable接口实现。Callable接口使用泛型去定义它的返回类型,它的参数类型表示的是从方法call()(不是run())中返回的值,下面简单说一下用用法。
首先定义一个类实现java.util.concurrent包下的Callable接口,然后重写里面的call方法(相当于其他方法的run()函数),创建ExecutorService线程池,将自定义类的对象放入线程池里面,即可获取线程的返回结果,最后,关闭线程池,不再接收新的线程,未执行完的线程不会被关闭。简单的示例如下:
public static void main(String[] args) {
//创建线程池对象
ExecutorService pool &#