多线程、线程池及AsyncTask

19 篇文章 0 订阅
8 篇文章 0 订阅

基本概念

  1. 进程和线程
  • 进程:资源分配的最小单位
  • 线程:独立运行的最小单位
  1. 并行和并发
  • 并行:同时执行,举例子来说,就是高速公路上4辆车可以并排着跑,双核四线程的并行度是4,可以同时运行4个线程
  • 并发:单位时间内,能执行的个数,举例来说,单位时间内可以通过的车的数量

线程

  1. 实现方式
  • 继承Thread
  • 实现Runnable接口
  • 实现Callable接口:线程执行结束后有返回值
//方式一
class UserThread extends Thread{
	public void run(){}
}
 new UserThread().start();
//方式二
class UserRunnable implements Runnable{
	public void run(){}
}
new Thread(new UserRunnable()).start();
//方式三
class UserCall implements Callable<String>{
	public String call() throws Exception{
		return "CallResult";
	}
}
UserCall call=new UserCall();
FutureTask<String> task=new FUtureTask<>();
new Thread(task).start();
//拿到执行结果
String result=task.get();
  1. 终止线程
  • interrupt :中断线程,协作式,非抢占式
  • interrupted :判断线程是否被中断了,判断过之后把中断状态由true改为false
  • isInterrupted : 判断线程是否被中断了
class UseThread extends Thread{
    public void run(){
        String threadName=Thread.currentThread().getName();
        while(!isInterrupted){
            System.out.println(threadName+" is running");
        }
        System.out.println(threadName+" end ");
    }
}

main(){
    Thread endThread = new UseThread("endThread");
    endThread.start();
    Thread.sleep(10);
    endThread.interrupt();
}
  1. 理解run和start
  • 直接run是执行普通方法
  • start才会创建线程
  1. 几个重要的关键字
  • join:把指定线程加入到当前线程中去,任务的插队,线程顺序执行时会用到
  • yield:当前线程让出CPU执行权,将线程从运行转到可运行状态
  • wait:等待,是Object的方法,线程执行需要的资源还不满足,需要阻塞等待响应资源满足后来唤醒
  • notify/notifyAll:通知,是Object的方法,notify通知一个等待的线程,notifyAll通知所有等待的线程
等待通知的标准范式
一、等待方:
1. 获取对象的锁
2. 检查条件,条件不满足 wait
3. 条件满足,执行业务代码
syn(对象){
    while(条件不满足){
        对象.wait();
    }
    //执行业务代码
}
二、通知方
1. 获取对象的锁
2. 修改条件
3. 通知等待方
syn(对象){
    //执行业务代码,修改条件
    对象.notifyAll/notify
}
  • sleep: 线程休眠
  • synchronized内置锁:
用处、
对象锁: 修改对象或者方法
类锁: static和synchronized 同时修饰某个方法,锁的是某个类的class对象
  • volatile:易变的,保证数据的可见性,不能保证操作的原子性,告诉虚拟机这个变量经常变化,每次用的时候都从内存中访问,不从内存缓存中访问
  • 乐观锁和悲观锁
悲观锁:更改数据时,一定要抢到锁
乐观锁:更改数据时,不会有人和我强,
    1. 先get到数据 oldValue
    2. 写回 newValue
        CAS( Compare and Swap)
        a.比较 数据=oldValue
        b.写回newValue
  • ThreadLocal: 解决线程间共享数据
  • Lock显示锁
lock:
tryLock:
unlock:

可重入锁ReentrantLock,所谓锁的公平和非公平,非公平比公平效率更好,非公平减少了上下文切换
1. 公平锁:先申请锁的先拿到
2. 非公平锁:多个线程去申请锁时,可能后面申请锁的先拿到

ReadWriteLock接口
读写锁ReentrantReadWriteLock
Condition接口
用Lock和Condition实现等待通知
//Lock的使用
class Test{
    int count=0;
    Lock lock=new ReentrantLock();

    voud incr(){
        lock.lock();
        try{
            count++;
        }finally{
            lock.unlock();
        }
    }
}
//读写锁
class UseRwLock{
    GoodsInfo goodsInfo;
    final ReadWriteLock lock=new ReentrantReadWriteLock();
    Lock getLock=lock.readLock();
    Lock setLock=lock.writeLock();
    
    GoodsInfo getNum(){
        getLock.lock();
        try{
            sleep(2s);
            return goodsInfo.getNum();
        }finally{
            getLock.unlock();
        }
    }
    void setNum(int count){
        setLock.lock();
        try{
            sleep(2s);
            return goodsInfo.setNum(count);
        }finally{
            setLock.unlock();
        }
    }
}
//用Lock和Condition实现等待通知
class TestCondition{
    Lock lock=new ReentrantLock();
    Condition kmCon=lock.newCondition();
    
    void changeKm(){
        lock.lock();
        try{
            this.km=101;
            kmCon.signal();
        }finally{
            lock.unlock();
        }
    }
    void waitKm(){
        lock.lock();
        try{
            while(this.km<100){
                try{
                    kmCon.wait();
                    int iKm=this.km;
                }
            }
        }finally{
            lock.unlock();
        }
    }
}
  1. 死锁
  • 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

线程池

  1. Linux允许创建的线程是1000个,每个线程占1M空间,Windows允许创建的线程是2000个
  2. 创建、销毁线程需要资源,所以要复用线程,使用线程池
  3. 线程池的好处
  • 复用线程,降低
  • 提高响应速度
  • 提高线程的可管理性
  1. JDK中实现的线程池:ThreadPoolExecutor
  • 线程池创建的核心参数
* corePoolSize: 核心线程数
* maximunPoolSize: 最大线程数
* keepAliveTime:线程空闲下来时候存活多久
* BlockingQueue<Runnable>:阻塞队列;阻塞插入方法:队列满,放元素被阻塞;阻塞移除方法:队列空,拿元素阻塞;
* ThreadFactory:给线程池命名的,缺省规则:pool+数字+thread+数字
* RejectedExecutionHandler: 
	缺省策略:
	DiscrdOldestPolicy: 丢弃队列中最靠前的任务
	AbortPolicy:直接丢弃
	CallerRunsPolicy:谁提交任务,这个任务由谁来执行
	DiscardPolicy:直接丢弃
  • 提交任务
execute:没有返回值
submit: 有返回值,返回Future
  • 合理配置线程池
任务的特性有关:
1. CPU密集型:大量的计算任务,线程池数量不要超过CPU上同时运行的线程个数 Runtime.getRuntime().availableProcessors
2. IO密集型:和IO操作有关,2*机器上CPU的个数
3. 混合型:拆分成上述两种

AsyncTask源码解析

  1. 线程池配置
//获取CPU核心数
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//线程池的核心线程数,最小2个,最大4个
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//线程池的最大线程数,线程数常用配置,此处+1是考虑到线程有时候从内存中读取数据时会因为页缺失而读不到数据,此时会通过IO读取数据,CPU将处于闲置状态,+1是为了不让CPU空闲
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//如果线程空闲,将在30秒后杀死该线程
    private static final int KEEP_ALIVE_SECONDS = 30;
//根据上述参数,创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
  1. SerialExecutor实现任务串行化
private static class SerialExecutor implements Executor {
		//任务队列
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
        	//从队列中取出一个任务
            mTasks.offer(new Runnable() {
                public void run() {
                	//一个任务执行完后再执行下一个任务
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }
  1. 任务的执行控制
//用户调用execute方法进行执行
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
		//execute中调用 executeOnExecutor
        return executeOnExecutor(sDefaultExecutor, params);
    }
//
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
         //1. 检查状态
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;
		//回调执行前方法
        onPreExecute();

        mWorker.mParams = params;
        //执行任务
        exec.execute(mFuture);

        return this;
    }

mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                	//拿到线程执行结果后做对应的处理
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };

private void postResultIfNotInvoked(Result result) {
        final boolean wasTaskInvoked = mTaskInvoked.get();
        if (!wasTaskInvoked) {
            postResult(result);
        }
    }

private Result postResult(Result result) {
		//通过handler把执行结果回调到主线程中去
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

private static class InternalHandler extends Handler {
        public InternalHandler(Looper looper) {
            super(looper);
        }

        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    //异步执行结果回调到主线程中去,finish方法中会回调 onPostExecute 方法,从而让AsyncTask的实现类的onPostExecute收到该回调
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值