Android 中多线程的简单使用
2016-05-10 13:38
686 查看
一、多线程的实现
1.最简单的启动一下新线程
或者:
实际上查看源码可以知道:Thread也是一个Runable,它实现Runable接口,在Thread类中有一个Runable类型的target字段,代表这个要执行在这个子线程中的任务。
Thread中默认的run方法源码为:
2.线程中waite、sleep、join、yield方法
wait(): 当一个线程执行到wait() 方法时,它就进入到了一个和该对象相关的等待池中,同时失去(释放)了对象的机锁,使得其他线程可以访问。用户可以使用notify,notifyAll或者指定睡眠时间来唤醒当前等待池中的线程。
sleep(): 该方法时Thread的静态函数,作用是使调用线程进入睡眠状态。因为sleep()是Thread()类的static 方法。因此他不能改变对象的机锁。所以当一个synchronized快中调用sleep()方法时,线程虽然睡眠了,但是对象的机锁并没有被释放,其他线程无法访问到这个对象。(即使睡着也持有这对象锁)
join(): 等待目标线程执行完成之后,再继续执行。
yield(): 线程礼让,目标线程由运行状态转换为就绪状态,也就是让出执行权限,让其他线程得以优先执行,但其他线程是否优先执行时未知的。
简单示例:
wait()示例:
join() 示例:
yield()示例:
3、与多线程相关的方法—–Callable、Future、FutureTask
Callable 与Runable的功能大致相似,不同的是Callable是一个泛型接口,它有一个泛型的参数V ,该接口有一个返回值(类型为V)的call 函数而Runable 的run()函数不能将结果返回给客户程序。Callable的声明如下:
而 Future为线程池制定了一个可管理的任务标准,它提供了对Runable或者Callable任务的执行结果进行取消,查询是否完成、获取结果、设置结果操作、分别对应cancel、isDone、get、set函数。get方法会阻塞,直到任务返回结果。future声明如下:
Future 只是定义了一些规范的接口,而FutureTask则是它的实现类。FutureTask实现了RunableFuture< V > 而RunableFuture又 继承自 Runable,和Ruture< V > 这两个接口,因此FutureTask具备了他们的能力。FutureTask代码如下:
FutureTask会像Thread包装Runable 那样包装 Callable,或者Runable
参考FutureTask的构造方法:
其中第二个构造方法,调用Executors.callable()函数将一个runnable转换成一个实现Callable接口的类。参考代码:
由于FutureTask实现了Runable ,因此,它既可以通过Thread包装来直接执行,也可以提交给ExcuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,知道结果返回。因此FutureTask既是Future,Runable,又包装了Callable,(如果Runnable最终也会被转换为Callable),他是这两者的合体。
代码示例:
二、线程池
线程池的优点:
(1) 重用存在的线程,减少对象的创建,销毁的开销
(2)可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多的资环竞争,避免堵塞;
(3) 提供定时执行,定期执行,单线程、并发数控制等功能。
线程池都实现了ExecuteService接口,该接口定义了线程池需要实现的接口。如submit、excute、shutdow、等方法
它的实现有 ThreadPoolExecutor和ScheduledThreadPoolExecutor。
1、启动指定数量的线程——ThreadPoolExecutor
ThreadPoolExecutor的构造方法如下:
corePoolSize: 线程池所保存的核心线程数,线程池启动后默认是空的,只有任务来临时才会创建线程以处理请求。prestartCoreThreads方法可以在线程池启动后即启动所有核心线程一等待任务。
maximumPoolSize: 线程池允许创建的最大线程数,当workQueue使用无界队列时(如LinkedBlockingQueue),则此参数无效。它与corePoolSize的作用是调整“线程池中实际运行的线程数量” 。例如,当新任务提交给线程池时,如果线程池中的运行线程数量小于corePoolSize,则创建新线程来处理请求,如果此时,线程池中的运行线程数量大于corePoolSize,但小于maximumPoolSize,则仅当阻塞队列满时才创建新线程,如果设置的corePoolSize 和maximumPoolSize 相同,则创建了固定大小的线程池,如果将maxiumPoolSize设置为基本的无界值(如: Integer.MAX_VALUE),则允许线程池适应任意数量的并发任务。
keepAliveTime: 当前线程池线程总数大于核心线程数时,终止多余的空闲线程的时间。
Unit: keepAliveTime参数的时间单位,可选值有毫秒,秒,分等。
workerQueue: 任务队列,如果当前线程池,达到核心线程数corePoolSize,且当前所有线程都处于活动状态时,则将新加入的任务放到此队列中。
threadFactory: 线程工厂,让用户可以定制线程的创建过程,通常不需要设置。
Handle : 决绝策略,当线程池与workQueue队列都满了的情况下,对新任务采取的处理策略。
1.最简单的启动一下新线程
private void startNewThread(){ new Thread(){ @Override public void run() { //耗时操作 } }.start(); }
或者:
private void startNewThread(){ new Thread(new Runnable() { @Override public void run() { //耗时操作 } }){}.start(); }
实际上查看源码可以知道:Thread也是一个Runable,它实现Runable接口,在Thread类中有一个Runable类型的target字段,代表这个要执行在这个子线程中的任务。
Thread中默认的run方法源码为:
@Override public void run() { if (target != null) { target.run(); } }
2.线程中waite、sleep、join、yield方法
wait(): 当一个线程执行到wait() 方法时,它就进入到了一个和该对象相关的等待池中,同时失去(释放)了对象的机锁,使得其他线程可以访问。用户可以使用notify,notifyAll或者指定睡眠时间来唤醒当前等待池中的线程。
sleep(): 该方法时Thread的静态函数,作用是使调用线程进入睡眠状态。因为sleep()是Thread()类的static 方法。因此他不能改变对象的机锁。所以当一个synchronized快中调用sleep()方法时,线程虽然睡眠了,但是对象的机锁并没有被释放,其他线程无法访问到这个对象。(即使睡着也持有这对象锁)
join(): 等待目标线程执行完成之后,再继续执行。
yield(): 线程礼让,目标线程由运行状态转换为就绪状态,也就是让出执行权限,让其他线程得以优先执行,但其他线程是否优先执行时未知的。
简单示例:
wait()示例:
public class MyClass { // 用于等待、唤醒的对象 private static Object sLockObject = new Object(); static void waitAndNotityAll() { System.out.println("主线程中执行"); // 创建并启动子线程 Thread thread = new WaiteThread(); thread.start(); long startTime = System.currentTimeMillis(); try { synchronized (sLockObject) { System.out.println("主线程等待"); sLockObject.wait(); } } catch (Exception e) { } long timeMs = System.currentTimeMillis() - startTime; System.out.println("主线程继续--等待耗时: " + timeMs + " ms"); } // 等待线程 static class WaiteThread extends Thread { @Override public void run() { try { synchronized (sLockObject) { Thread.sleep(3000); sLockObject.notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args){ waitAndNotityAll(); } } 执行结果: 主线程中执行 主线程等待 主线程继续--等待耗时: 3001 ms
join() 示例:
public class JoinTest { static void joinDemo(){ Worker worker1 = new Worker("worker-1"); Worker worker2 = new Worker("worker-2"); worker1.start(); System.out.println("启动线程1"); try { // 调用worker1的join函数,主线程会阻塞直到worker1执行完成 worker1.join(); System.out.println("启动线程2"); worker2.start(); worker2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主线程继续执行"); } static class Worker extends Thread{ public Worker(String name){ super(name); } @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("work in " +getName()); } } public static void main(String[] args){ joinDemo(); } } 执行结果: 启动线程1 work in worker-1 启动线程2 work in worker-2 主线程继续执行
yield()示例:
public class YieldTest { public static final int MAX = 5; static class YieldThread extends Thread { public YieldThread(String name) { super(name); } public synchronized void run() { for (int i = 0; i < MAX; i++) { System.out.printf("%s priority: [%d]------> %d\n", this.getName(), this.getPriority(), i); // 当i==2 是,调用当前线程的yield函数。 if (i == 2) { Thread.yield(); } } } } static void yieldDemo() { YieldThread t1 = new YieldThread("thread-1"); YieldThread t2 = new YieldThread("thread-2"); t1.start(); t2.start(); } public static void main(String[] args) { yieldDemo(); } } 可能没有效果
3、与多线程相关的方法—–Callable、Future、FutureTask
Callable 与Runable的功能大致相似,不同的是Callable是一个泛型接口,它有一个泛型的参数V ,该接口有一个返回值(类型为V)的call 函数而Runable 的run()函数不能将结果返回给客户程序。Callable的声明如下:
public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
而 Future为线程池制定了一个可管理的任务标准,它提供了对Runable或者Callable任务的执行结果进行取消,查询是否完成、获取结果、设置结果操作、分别对应cancel、isDone、get、set函数。get方法会阻塞,直到任务返回结果。future声明如下:
public interface Future<V> { //取消任务 boolean cancel(boolean mayInterruptIfRunning); //任务是否已经取消 boolean isCancelled(); //任务是否已经完成 boolean isDone(); //获取结果,如果任务未完成,则等待,直到完成,因此该函数会阻塞 V get() throws InterruptedException, ExecutionException; //获取结果,如果还未完成那么等待,直达timeout 或者返回结果,该函数会阻塞 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future 只是定义了一些规范的接口,而FutureTask则是它的实现类。FutureTask实现了RunableFuture< V > 而RunableFuture又 继承自 Runable,和Ruture< V > 这两个接口,因此FutureTask具备了他们的能力。FutureTask代码如下:
public class FutureTask<V> implements RunnableFuture<V> { ....... }
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
FutureTask会像Thread包装Runable 那样包装 Callable,或者Runable
参考FutureTask的构造方法:
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
其中第二个构造方法,调用Executors.callable()函数将一个runnable转换成一个实现Callable接口的类。参考代码:
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); } /** * A callable that runs given task and returns given result */ static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }
由于FutureTask实现了Runable ,因此,它既可以通过Thread包装来直接执行,也可以提交给ExcuteService来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,知道结果返回。因此FutureTask既是Future,Runable,又包装了Callable,(如果Runnable最终也会被转换为Callable),他是这两者的合体。
代码示例:
public class FutureDemo { // 线程池 static ExecutorService mExecutor = Executors.newSingleThreadExecutor(); public static void main(String[] args){ try { futureWithRunable(); futureWithCallable(); futureTask(); }catch (Exception e){ } } private static void futureTask() throws ExecutionException, InterruptedException { FutureTask<Integer> futureTask =new FutureTask<Integer>(new Callable<Integer>() { @Override public Integer call() throws Exception { return fibc(20); } }) ; //提交futureTask mExecutor.submit(futureTask); System.out.println("future result from futureTask : "+futureTask.get()); } private static void futureWithCallable() throws ExecutionException, InterruptedException { final Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { return fibc(20); } }) ; System.out.println("future reuslt from callable: "+result2.get()) ; } private static void futureWithRunable() throws ExecutionException, InterruptedException { // 提交runable,没有返回值,future没有数据 Future<?> result = mExecutor.submit(new Runnable() { @Override public void run() { fibc(20); } }); System.out.println("future result from runable : "+result.get()); } private static int fibc(int num){ if(num==0){ return 0; } if(num==1){ return 1 ; } return fibc(num-1) +fibc(num-2); } }
二、线程池
线程池的优点:
(1) 重用存在的线程,减少对象的创建,销毁的开销
(2)可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多的资环竞争,避免堵塞;
(3) 提供定时执行,定期执行,单线程、并发数控制等功能。
线程池都实现了ExecuteService接口,该接口定义了线程池需要实现的接口。如submit、excute、shutdow、等方法
它的实现有 ThreadPoolExecutor和ScheduledThreadPoolExecutor。
1、启动指定数量的线程——ThreadPoolExecutor
ThreadPoolExecutor的构造方法如下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
corePoolSize: 线程池所保存的核心线程数,线程池启动后默认是空的,只有任务来临时才会创建线程以处理请求。prestartCoreThreads方法可以在线程池启动后即启动所有核心线程一等待任务。
maximumPoolSize: 线程池允许创建的最大线程数,当workQueue使用无界队列时(如LinkedBlockingQueue),则此参数无效。它与corePoolSize的作用是调整“线程池中实际运行的线程数量” 。例如,当新任务提交给线程池时,如果线程池中的运行线程数量小于corePoolSize,则创建新线程来处理请求,如果此时,线程池中的运行线程数量大于corePoolSize,但小于maximumPoolSize,则仅当阻塞队列满时才创建新线程,如果设置的corePoolSize 和maximumPoolSize 相同,则创建了固定大小的线程池,如果将maxiumPoolSize设置为基本的无界值(如: Integer.MAX_VALUE),则允许线程池适应任意数量的并发任务。
keepAliveTime: 当前线程池线程总数大于核心线程数时,终止多余的空闲线程的时间。
Unit: keepAliveTime参数的时间单位,可选值有毫秒,秒,分等。
workerQueue: 任务队列,如果当前线程池,达到核心线程数corePoolSize,且当前所有线程都处于活动状态时,则将新加入的任务放到此队列中。
threadFactory: 线程工厂,让用户可以定制线程的创建过程,通常不需要设置。
Handle : 决绝策略,当线程池与workQueue队列都满了的情况下,对新任务采取的处理策略。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试