android多线程有什么用,关于Android多线程的理解

扩展知识

线程和进程有什么区别?

一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

多线程编程的好处是什么?

多个线程被并发的执行以提高程序的效率,提高CPU和内存利用率

什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?

线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(也就是说不要让你的程序依赖于线程的优先级)。

什么是ThreadLocal?

ThreadLocal用于创建线程的本地变量,我们知道一个对象的所有线程会共享它的全局变量,所以这些变量不是线程安全的,我们可以使用同步技术。但是当我们不想使用同步的时候,我们可以选择ThreadLocal变量。

ThreadLocal是数据的隔离,但是并非数据的复制,而是在每一个线程中创建一个新的数据对象,然后每一个线程使用的是不一样的。

每个线程都会拥有他们自己的Thread变量,它们可以使用get()\set()方法去获取他们的默认值或者在线程内部改变他们的值。ThreadLocal实例通常是希望它们同线程状态关联起来是private static属性。

什么是线程池

一个线程池管理了一组工作线程,同时它还包括了一个用于放置等待执行的任务的队列。

创建线程

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

1、继承Thread类实现多线程

继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:

public class MyThread extends Thread {

public void run() {

System.out.println("MyThread.run()");

}

}

在合适的地方启动线程如下:

MyThread myThread1 = new MyThread();

MyThread myThread2 = new MyThread();

myThread1.start();

myThread2.start();

2、实现Runnable接口方式实现多线程

如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口,如下:

public class MyThread extends OtherClass implements Runnable {

public void run() {

System.out.println("MyThread.run()");

}

}

为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:

MyThread myThread = new MyThread();

Thread thread = new Thread(myThread);

thread.start();

事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:

public void run() {

if (target != null) {

target.run();

}

}

3、使用ExecutorService、Callable、Future实现有返回结果的多线程。

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子

注意:get方法是阻塞的,即:线程无返回结果,get方法会一直等待

Log.w("TAG", "----程序开始运行----");

Date date1 = new Date();

int taskSize = 2;

// 创建一个线程池

ExecutorService pool = Executors.newFixedThreadPool(taskSize);

// 创建多个有返回值的任务

List list = new ArrayList();

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

Callable c = new MyCallable(i + " ");

// 执行任务并获取Future对象

Future f = pool.submit(c);

// System.out.println(">>>" + f.get().toString());

list.add(f);

}

// 关闭线程池

pool.shutdown();

// 获取所有并发任务的运行结果

for (Future f : list) {

// 从Future对象上获取任务的返回值,并输出到控制台

try {

Log.w("TAG", ">----123-->>" + f.get().toString());

} catch (ExecutionException e) {

e.printStackTrace();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

Date date2 = new Date();

Log.w("TAG", "----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");

}

public class MyCallable implements Callable {

private String taskNum;

public MyCallable(String taskNum) {

this.taskNum = taskNum;

}

public Object call() throws Exception {

Log.w("TAG", ">call---->>" + taskNum + "任务启动");

Date dateTmp1 = new Date();

Thread.sleep(3000);

Date dateTmp2 = new Date();

long time = dateTmp2.getTime() - dateTmp1.getTime();

Log.w("TAG", ">>>" + taskNum + "任务终止");

return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";

}

}

执行结果,两个任务中止后,将结果返回

W/TAG: ----程序开始运行----

W/TAG: >call---->>0 任务启动

W/TAG: >call---->>1 任务启动

W/TAG: >>>0 任务终止

W/TAG: >----123-->>0 任务返回运行结果,当前任务时间【3006毫秒】

W/TAG: >>>1 任务终止

W/TAG: >----123-->>1 任务返回运行结果,当前任务时间【3005毫秒】

W/TAG: ----程序结束运行----,程序运行时间【3029毫秒】

关于线程池

ExecutorService与生命周期

ExecutorService扩展了Executor并添加了一些生命周期管理的方法。一个Executor的生命周期有三种状态,运行 ,关闭 ,终止 。Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true。

如果Executor处于关闭状态,往Executor提交任务会抛出unchecked exception RejectedExecutionException。

Java通过Executors提供四种线程池,分别为:

CachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。在线程空闲60秒后终止线程。

②最大线程数Integer.MAX_VALUE,最多65535个线程

③超时时间60s

ScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

FixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

SingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

②最大线程数Integer.MAX_VALUE,最多65535个线程

他就是线程数量为1的FixedThreadPool,如果向SingleThreadExecutor提交多个任务,那么这些任务会排队,每个任务都会在下个任务开始之前就结束,所有任务都用一个线程,并且按照提交的顺序执行。

①一个核心线程

具体的注释可以点击进去参考源码,

ExecutorService pool1 = Executors.newCachedThreadPool();

ExecutorService pool2 = Executors.newFixedThreadPool(3);

ExecutorService pool3 = Executors.newScheduledThreadPool(3);

ExecutorService pool4 = Executors.newSingleThreadExecutor();

Executors类用于管理Thread对象,简化并发过程,我们可以看到FixedThreadPool的创建过程:

public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads,

0L, TimeUnit.MILLISECONDS,

new LinkedBlockingQueue());

}

显然这四种线程池方法都是返回实现了ExecutorService接口的ThreadPoolExecutor。

Executor是Java中的概念,是一个接口,真正的线程池实现是ThreadPoolExecutor。它提供了一系列的参数来配置不同的线程池。当然我们也可以直接用ThreadPoolExecutor来自定义更灵活的线程池。

public ThreadPoolExecutor(

int corePoolSize,//核心线程数

int maximumPoolSize,//最大线程数

long keepAliveTime, //非核心线程的超时时间

TimeUnit unit,//单位

BlockingQueue workQueue,//任务队列

ThreadFactory threadFactory//线程工厂

RejectedExecutionHandler handler)

corePoolSize

核心线程数,核心线程池默认会在线程池中一直存活,无论它是不是闲置。如果将ThreadPoolExecute的allowCoreThreadTimeOut设置为true,那么闲置的核心线程会执行超时策略,这个超时策略的时间间隔是由keepAliveTime所指定的。

maximumPoolSize

线程池所能容纳的最大线程数,当活动的线程数达到这个数值后,后续的任务会被阻塞。

keepAliveTime

非核心线程池的超时时长,非核心线程池闲置的时间超过这个时间就会被回收。当ThreadPoolExecute的allowCoreThreadTimeOut设置为true时,它同样也作用于核心线程。

unit

用于指定keepAliveTime的单位。

workQueue

线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会储存在这个参数中。

threadFactory

线程工厂,为线程池提供创建新线程的功能,ThreadFactory是一个接口,他只有一个方法:

public interface ThreadFactory {

Thread newThread(Runnable var1);

}

除了这些参数外还有个很不常用的参数RejectedExecutionHandler handler。当线程池无法执行新任务时(任务队列满了或者无法成功执行)会调用handler的rejectExecutionException。

4c4e53f494d6

执行步骤

Android线程间通信方式之AsyncTask机制

Handler机制;

runOnUiThread方法,用Activity对象的runOnUiThread方法更新,在子线程中通过runOnUiThread()方法更新UI

View.post(Runnable r) 、

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值