Android 中多线程的简单使用

一、多线程的实现
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队列都满了的情况下,对新任务采取的处理策略。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值