Thread和handler,线程,线程池

 

线程Thread

1,线程使用中有两种将使用线程关闭的方法  a.加标志位,b, Thread.interrupt();

2,标志位例子:设置仪表标志位,通过set放发外界进行停止线程中的循环

class MyThread extends Thread{

        private volatile boolean isStop = false;

        @Override

        public void run() {

            int i = 0;

            while(!isStop){

                i++;

            }

        }
        

        public void setStop(boolean stop){

            this.isStop = stop;

        }

    }

 

Thread.interrupt(); Thread=null;虽然能中断线程但是不能中断线程中已经执行的线程,可以在已经执行的线程中判断一下 isInterrupted()线程是否被终止

Thread.sleep(1000);是让正在执行的线程休眠   Thread mThread=Thread.currentThread();当前线程

异常法停止线程

myThread.setPriority(1);线程优先级,线程的优先级用1-10之间的整数表示,数值越大优先级越高,默认的优先级为5。

在线程调用的外部方法,为了线程安全,调用的方法应该使用同步关键字synchroinzed

 

 

线程间通信

1,Handler消息 

2,共享内存(全局变量)

3,管道流(PipOutP)

4,Broadcast Receiver

5,EventBus

6,runOnUiThread(),view.post()

7,AsyncTask

 

 

 

sleep和wait的区别有:

  1,这两个方法来自不同的类分别是Thread和Object
  2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
    任何地方使用
   synchronized(x){
      x.notify()
     //或者wait()
   }
   4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
sleep指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制。
wait指线程处于进入等待状态,形象地说明为“等待使用CPU”,此时线程不占用任何资源,不增加时间限制。

wait()方法表示,放弃当前对资源的占有权,等啊等啊,一直等到有人通知我,我才会运行后面的代码。 
notify()方法表示,当前的线程已经放弃对资源的占有, 
通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复, 
然后继续运行wait()后面的语句; 
notifyAll()方法表示,当前的线程已经放弃对资源的占有, 
通知所有的等待线程从wait()方法后的语句开始运行。 

 

 

与handler有关

handler机制就是android消息机制

  • 主线程不能执行耗时操作(避免ANR)
  • 子线程不能直接更新UI界面

主线程,ActivityThread被创建的时候就会创建Looper
Looper被创建的时候创建MessageQueue。
也就是说主线程会直接或简介创建出来Looper和MessageQueue。

 

 

注意: 我们常常用Handler来更新UI,但是不是说Handler就是把用来更新UI的,我们的耗时的I/O操作,读取文件,访问网络等等都是可以在Handler里面操作的

Looper是一个轮询器,它的作用不断轮询MessageQueue,当如果有新的消息就交给Handler处理,如果轮询不到新的消息,那就自身就处于阻塞状态。

 

new Handler的hanlder不能没有Looper(在主线程默认就有loop,所以每次new不需要获取主线程loop)

Handler主要工作

 

主要工作:消息的 发送 send和 处理handerMessage

New Handler必须有loop,没有loop就要使用Looper.prepare()方法生成handler,使用hander发送message到消息队列,接着调用Looper.loop()不断遍历消息队列,拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue

Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()Handler , sendMessageMessageQueueLooper不断

MessageQueue中取出消息,回调handleMessage方法。

 

 

 

处理Handler的内存泄漏

 

1,弱引用

private NoLeakHandler mHandler;

@Override protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mHandler = new NoLeakHandler(this);

Message message = Message.obtain();

mHandler.sendMessageDelayed(message,10*60*1000); }

private static class NoLeakHandler extends Handler{

private WeakReference<NoLeakActivity> mActivity;

public NoLeakHandler(NoLeakActivity activity){ mActivity = new WeakReference<>(activity); }

@Override public void handleMessage(Message msg) {

super.handleMessage(msg); }

}

2,页面销毁的时候调用

if (mHandler != null) mHandler.removeCallbacksAndMessages(null);
或者:
mhandler.removeCallbacks(runnable);
mhandler=null;

可以释放将要执行的,但是已经执行的,比如延时需要在操作里面判空处理。

 

如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其它线程访问UI线程:

·      Activity.runOnUiThread(Runnable)

·      View.post(Runnable)

·      View.postDelayed(Runnable, long)

·      Handler

 

 

(1)安排消息或Runnable 在某个主线程中某个地方执行;

(2)安排一个动作在不同的线程中执行。

Handler中分发消息的一些方法

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列中,

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新。

  Handler主要有两种用途:

  1.合理调度安排消息和runnable对象,使它们在将来的某个点被执行。

  2.将一个动作入队安排在非当前线程执行。

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

 

·      Handler的处理过程运行在创建Handler的线程里

·      一个Looper对应一个MessageQueue

·      一个线程对应一个Looper

·      一个Looper可以对应多个Handler

·      不确定当前线程时,更新UI时尽量调用post方法

 

 

private Handler mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case 1:
                     break;
          
        }
        mItemId = -1;
        return true;
    }
});

 

 

 

 

 

线程池

2.使用线程池的好处

1.重用已经创建的好的线程,避免频繁创建进而导致的频繁GC

2.控制线程并发数,合理使用系统资源,提高应用性能

3.可以有效的控制线程的执行,比如定时执行,取消执行等

Java代码  

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核心线程池大小
maximumPoolSize最大线程池大小
keepAliveTime线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
TimeUnitkeepAliveTime时间单位
workQueue阻塞任务队列
threadFactory新建线程工厂
RejectedExecutionHandler当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理

 

重点讲解: 
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。 

1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。 
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 
3.当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务 
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程 
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭 

线程管理机制图示: 

 

总结:

随着任务数量的增加,会增加活跃的线程数。

当活跃的线程数 =   核心线程数,此时不再增加活跃线程数,而是往任务队列里堆积。

当任务队列堆满了,随着任务数量的增加,会在核心线程数的基础上加开线程。

直到活跃线程数 = 最大线程数,就不能增加线程了。

如果此时任务还在增加,则: 任务数 > 最大线程数 + 队列长度 ,抛出异常RejectedExecutionException,拒绝任务。

 

 

 

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


newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

 

4.FixedThreadPool

FixedThreadPool是一个核心线程数量固定的线程池,创建方式如下:

 

[java] view plain copy print?

  1. ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);  


源码如下:[java] view plain copy print?

  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.         return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                       0L, TimeUnit.MILLISECONDS,  
  4.                                       new LinkedBlockingQueue<Runnable>());  
  5.     }  


我们看到核心线程数和最大线程数一样,说明在FixedThreadPool中没有非核心线程,所有的线程都是核心线程,且线程的超时时间为0,说明核心线程即使在没有任务可执行的时候也不会被销毁(这样可让FixedThreadPool更快速的响应请求),最后的线程队列是一个LinkedBlockingQueue,但是LinkedBlockingQueue却没有参数,这说明线程队列的大小为Integer.MAX_VALUE(2的31次方减1),OK,看完参数,我们大概也就知道了FixedThreadPool的工作特点了,当所有的核心线程都在执行任务的时候,新的任务只能进入线程队列中进行等待,直到有线程被空闲出来。OK,我们来看一个Demo:

 

[java] view plain copy print?

  1. ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);  
  2.         for (int i = 0; i < 30; i++) {  
  3.             final int finalI = i;  
  4.             Runnable runnable = new Runnable(){  
  5.                 @Override  
  6.                 public void run() {  
  7.                     SystemClock.sleep(3000);  
  8.                     Log.d("google_lenve_fb""run: "+ finalI);  
  9.                 }  
  10.             };  
  11.             fixedThreadPool.execute(runnable);  
  12.         }  


执行结果如下:

 

这执行结果也和我们想的一致,先往核心线程中添加三个任务,剩余任务进入到workQueue中等待,当有空闲的核心线程时就执行任务队列中的任务。

5.SingleThreadExecutor

singleThreadExecutor和FixedThreadPool很像,不同的就是SingleThreadExecutor的核心线程数只有1,如下:

 

[java] view plain copy print?

public static ExecutorService newSingleThreadExecutor() {  
    return new FinalizableDelegatedExecutorService  
        (new ThreadPoolExecutor(1, 1,  
                                0L, TimeUnit.MILLISECONDS,  
                                new LinkedBlockingQueue<Runnable>()));  
}  


使用SingleThreadExecutor的一个最大好处就是可以避免我们去处理线程同步问题,其实如果我们把FixedThreadPool的参数传个1,效果不就和SingleThreadExecutor一致了,来看个Demo:

 

 

[java] view plain copy print?

  1. ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();  
            for (int i = 0; i < 30; i++) {  
                final int finalI = i;  
                Runnable runnable = new Runnable() {  
                    @Override  
                    public void run() {  
                        Log.d("google_lenve_fb", "run: " + Thread.currentThread().getName() + "-----" + finalI);  
                        SystemClock.sleep(1000);  
                    }  
                };  
                singleThreadExecutor.execute(runnable);  
            }  
    

    执行效果如下:

 

6.CachedThreadPool

CachedTreadPool一个最大的优势是它可以根据程序的运行情况自动来调整线程池中的线程数量,CachedThreadPool源码如下:

 

[java] view plain copy print?

  1. public static ExecutorService newCachedThreadPool() {  
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
                                      60L, TimeUnit.SECONDS,  
                                      new SynchronousQueue<Runnable>());  
    }  
    

    我们看到,CachedThreadPool中是没有核心线程的,但是它的最大线程数却为Integer.MAX_VALUE,另外,它是有线程超时机制的,超时时间为60秒,这里它使用了SynchronousQueue作为线程队列,SynchronousQueue的特点上文已经说过了,这里不再赘述。那么我们提交到CachedThreadPool消息队列中的任务在执行的过程中有什么特点呢?由于最大线程数为无限大,所以每当我们添加一个新任务进来的时候,如果线程池中有空闲的线程,则由该空闲的线程执行新任务,如果没有空闲线程,则创建新线程来执行任务。根据CachedThreadPool的特点,我们可以在有大量任务请求的时候使用CachedThreadPool,因为当CachedThreadPool中没有新任务的时候,它里边所有的线程都会因为超时而被终止。OK,我们来看一个Demo:

 

 

[java] view plain copy print?

  1. ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
            for (int i = 0; i < 30; i++) {  
                final int finalI = i;  
                Runnable runnable = new Runnable(){  
                    @Override  
                    public void run() {  
                        Log.d("google_lenve_fb", "run: " + Thread.currentThread().getName() + "----" + finalI);  
                    }  
                };  
                cachedThreadPool.execute(runnable);  
                SystemClock.sleep(2000);  
            }  
    

    每次添加完任务之后我都停两秒在添加新任务,由于这里的任务执行不费时,我们可以猜测这里所有的任务都使用同一个线程来执行(因为每次添加新任务的时候都有空闲的线程),运行结果如下:

 

和我们的想法基本一致。OK,那如果我把代码稍微改一下:

 

[java] view plain copy print?

  1. ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
            for (int i = 0; i < 30; i++) {  
                final int finalI = i;  
                Runnable runnable = new Runnable(){  
                    @Override  
                    public void run() {  
                        SystemClock.sleep(2000);  
                        Log.d("google_lenve_fb", "run: " + Thread.currentThread().getName() + "----" + finalI);  
                    }  
                };  
                cachedThreadPool.execute(runnable);  
                SystemClock.sleep(1000);  
            }  

     


每个任务在执行的过程中都先休眠两秒,但是我向线程池添加任务则是每隔1s添加一个任务,这样的话,添加第一个任务时先开新线程,添加第二个任务时,由于第一个新线程尚未执行完,所以又开一个新线程,添加第三个任务时,第一个线程已经空闲下来了,直接第一个线程来执行第三个任务,依此类推。我们来看看运行结果:

 

7.ScheduledThreadPool

ScheduledThreadPool是一个具有定时定期执行任务功能的线程池,源码如下:

 

[java] view plain copy print?

  1. public ScheduledThreadPoolExecutor(int corePoolSize) {  
        super(corePoolSize, Integer.MAX_VALUE,  
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,  
              new DelayedWorkQueue());  
    }  
    

     

 

 

我们可以看到,它的核心线程数量是固定的(我们在构造的时候传入的),但是非核心线程是无穷大,当非核心线程闲置时,则会被立即回收。

使用ScheduledThreadPool时,我们可以通过如下几个方法来添加任务:

1.延迟启动任务:

 

[java] view plain copy print?

  1. public ScheduledFuture<?> schedule(Runnable command,  
  2.                                    long delay, TimeUnit unit);  

示例代码:

 

 

[java] view plain copy print?

  1. ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);  
                Runnable runnable = new Runnable(){  
                    @Override  
                    public void run() {  
                        Log.d("google_lenve_fb", "run: ----");  
                    }  
                };  
            scheduledExecutorService.schedule(runnable, 1, TimeUnit.SECONDS);  
    

     

 

 

2.延迟定时执行任务:

 

[java] view plain copy print?

  1. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,  
  2.                                               long initialDelay,  
  3.                                               long period,  
  4.                                               TimeUnit unit);  


延迟initialDelay秒后每个period秒执行一次任务。示例代码:

 

 

[java] view plain copy print?

  1. ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);  
                Runnable runnable = new Runnable(){  
                    @Override  
                    public void run() {  
                        Log.d("google_lenve_fb", "run: ----");  
                    }  
                };  
            scheduledExecutorService.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);  

     


延迟1秒之后每隔1秒执行一次新任务。

 

 

 

3.延迟执行任务

 

[java] view plain copy print?

  1. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,  
  2.                                                  long initialDelay,  
  3.                                                  long delay,  
  4.                                                  TimeUnit unit);  


第一次延迟initialDelay秒,以后每次延迟delay秒执行一个任务。示例代码:

 

 

[java] view plain copy print?

  1. ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);  
  2.             Runnable runnable = new Runnable(){  
  3.                 @Override  
  4.                 public void run() {  
  5.                     Log.d("google_lenve_fb""run: ----");  
  6.                 }  
  7.             };  
  8.         scheduledExecutorService.scheduleWithFixedDelay(runnable, 11, TimeUnit.SECONDS);  


第一次延迟1秒之后,以后每次也延迟1秒执行。

 

 

OK,至此,Android开发中常用的线程池就说完了。

8.线程池其他常用功能


 setCorePoolSize()。设置/更改核心池的大小。
 setMaximumPoolSize(),设置/更改线程池中最大线程的数量限制。

1.shutDown()  关闭线程池,不影响已经提交的任务

2.shutDownNow() 关闭线程池,并尝试去终止正在执行的线程

3.allowCoreThreadTimeOut(boolean value) 允许核心线程闲置超时时被回收

4.submit 一般情况下我们使用execute来提交任务,但是有时候可能也会用到submit,使用submit的好处是submit有返回值,举个栗子:

 

[java] view plain copy print?

  1. public void submit(View view) {  
  2.     List<Future<String>> futures = new ArrayList<>();  
  3.     ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(351,  
  4.             TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());  
  5.     for (int i = 0; i < 10; i++) {  
  6.         Future<String> taskFuture = threadPoolExecutor.submit(new MyTask(i));  
  7.         //将每一个任务的执行结果保存起来  
  8.         futures.add(taskFuture);  
  9.     }  
  10.     try {  
  11.         //遍历所有任务的执行结果  
  12.         for (Future<String> future : futures) {  
  13.             Log.d("google_lenve_fb""submit: " + future.get());  
  14.         }  
  15.     } catch (InterruptedException e) {  
  16.         e.printStackTrace();  
  17.     } catch (ExecutionException e) {  
  18.         e.printStackTrace();  
  19.     }  
  20. }  
  21.   
  22. class MyTask implements Callable<String> {  
  23.   
  24.     private int taskId;  
  25.   
  26.     public MyTask(int taskId) {  
  27.         this.taskId = taskId;  
  28.     }  
  29.   
  30.     @Override  
  31.     public String call() throws Exception {  
  32.         SystemClock.sleep(1000);  
  33.         //返回每一个任务的执行结果  
  34.         return "call()方法被调用----" + Thread.currentThread().getName() + "-------" + taskId;  
  35.     }  
  36. }  


使用submit时我们可以通过实现Callable接口来实现异步任务。在call方法中执行异步任务,返回值即为该任务的返回值。Future是返回结果,返回它的isDone属性表示异步任务执行成功!

 

5. 自定义线程池

除了使用submit来定义线程池获取线程执行结果之外,我们也可以通过自定义ThreadPoolExecutor来实现这个功能,如下:

 

[java] view plain copy print?

  1. public void customThreadPool(View view) {  
  2.     final MyThreadPool myThreadPool = new MyThreadPool(351, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>());  
  3.     for (int i = 0; i < 10; i++) {  
  4.         final int finalI = i;  
  5.         Runnable runnable = new Runnable(){  
  6.             @Override  
  7.             public void run() {  
  8.                 SystemClock.sleep(100);  
  9.                 Log.d("google_lenve_fb""run: " + finalI);  
  10.             }  
  11.         };  
  12.         myThreadPool.execute(runnable);  
  13.     }  
  14. }  
  15. class MyThreadPool extends ThreadPoolExecutor{  
  16.   
  17.     public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {  
  18.         super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);  
  19.     }  
  20.   
  21.     @Override  
  22.     protected void beforeExecute(Thread t, Runnable r) {  
  23.         super.beforeExecute(t, r);  
  24.         Log.d("google_lenve_fb""beforeExecute: 开始执行任务!");  
  25.     }  
  26.   
  27.     @Override  
  28.     protected void afterExecute(Runnable r, Throwable t) {  
  29.         super.afterExecute(r, t);  
  30.         Log.d("google_lenve_fb""beforeExecute: 任务执行结束!");  
  31.     }  
  32.   
  33.     @Override  
  34.     protected void terminated() {  
  35.         super.terminated();  
  36.         //当调用shutDown()或者shutDownNow()时会触发该方法  
  37.         Log.d("google_lenve_fb""terminated: 线程池关闭!");  
  38.     }  
  39. }  
  40.  

http://blog.csdn.net/u012702547/article/details/52259529

线程池的关闭

public void stopThreadPool(ExecutorService pool, long timeout, TimeUnit unit) throws InterruptedException {
    try {
        pool.shutdown();
        // (所有的任务都结束的时候,返回TRUE)
        if (!pool.awaitTermination(1000L, TimeUnit.MILLISECONDS)) {
            // 超时的时候向线程池中所有的线程发出中断(interrupted)。
            pool.shutdownNow();
        }
    } catch (InterruptedException e) {
        // awaitTermination方法被中断的时候也中止线程池中全部的线程的执行。
        pool.shutdownNow();
    }
}

 

线程造成的内存泄漏处理


 


public class LeakAty extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.aty_leak);

test();

}

//加上static,变成静态匿名内部类

public static void test() {

new Thread(new Runnable() {

@Override

public void run() {

while (true) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}).start();

}

}







public class LeakAty extends Activity {

private TextView tvResult;

private MyHandler handler;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.aty_leak);

tvResult = (TextView) findViewById(R.id.tvResult);

handler = new MyHandler(this);

fetchData();

}

//第一步,将Handler改成静态内部类。

private static class MyHandler extends Handler {

//第二步,将需要引用Activity的地方,改成弱引用。

private WeakReference<LeakAty> atyInstance;

public MyHandler(LeakAty aty) {

this.atyInstance = new WeakReference<LeakAty>(aty);

}

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

LeakAty aty = atyInstance == null ? null : atyInstance.get();

//如果Activity被释放回收了,则不处理这些消息

if (aty == null||aty.isFinishing()) {

return;

}

aty.tvResult.setText("fetch data success");

}

}

private void fetchData() {

// 获取数据

handler.sendEmptyMessage(0);

}

@Override

protected void onDestroy() {

//第三步,在Activity退出的时候移除回调

super.onDestroy();

handler.removeCallbacksAndMessages(null);

}

}

 

自定义线程池管理

package com.xcm91.relation.mythread.utils;

import android.util.Log;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
 * @since 2017/3/13
 */

public class ThreadPoolManager {

    private static ThreadPoolProxy mInstance;
    //CPU核心数
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    //核心线程数
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;

    //最大线程数
    private static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1;

    public static ThreadPoolProxy getInstance() {
        if (mInstance == null) {
            synchronized (ThreadPoolManager.class) {
                if (mInstance == null) {
                    Log.i("ThreadPoolManager", "corePoolSize: " + CORE_POOL_SIZE + "----maximumPoolSize:" + MAX_POOL_SIZE);
                    mInstance = new ThreadPoolProxy(CORE_POOL_SIZE, MAX_POOL_SIZE);
                }
            }
        }

        return mInstance;
    }


    /**
     * 线程池代理
     * <p>
     * 线程池初始化方法
     * corePoolSize 核心线程池大小----2--- 线程池维护线程的最少数量
     * maximumPoolSize 最大线程池大小----5---线程池维护线程的最大数量
     * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit--线程池维护线程所允许的空闲时间
     * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES--线程池维护线程所允许的空闲时间的单位
     * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(5)==线程池所使用的缓冲队列==5容量的阻塞队列
     * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂
     * rejectedExecutionHandler 线程池对拒绝任务的处理策略,当提交任务数超过maxmumPoolSize+workQueue之和时,
     * 即当提交第41个任务时(前面线程都没有执行完),
     * 任务会交给RejectedExecutionHandler来处理
     */
    public static class ThreadPoolProxy {

        private ThreadPoolExecutor mThreadPoolExecutor;


        public ThreadPoolProxy(int corePoolSize, int maximumPoolSize) {
            initThreadPoolExecutor(corePoolSize, maximumPoolSize);
        }

        private void initThreadPoolExecutor(int corePoolSize, int maximumPoolSize) {

            if (mThreadPoolExecutor == null) {
//                ExecutorService executorService = Executors.newFixedThreadPool(3);
                //阻塞缓冲队列
                BlockingDeque<Runnable> workQueue = new LinkedBlockingDeque<>();

                //线程工厂
                ThreadFactory threadFactory = Executors.defaultThreadFactory();
                //拒绝任务处理策略(抛弃旧的任务)
                RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

                mThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MICROSECONDS, workQueue, threadFactory, handler);
            }
        }

        public void submit(Runnable task) {
            if (mThreadPoolExecutor != null) {
                mThreadPoolExecutor.submit(task);
            }
        }

        public void execute(Runnable task) {
            if (mThreadPoolExecutor != null) {
                mThreadPoolExecutor.execute(task);
            }
        }

        public void remove(Runnable task) {
            if (mThreadPoolExecutor != null && !mThreadPoolExecutor.isShutdown()) {
                mThreadPoolExecutor.remove(task);
            }
        }


        /**
         * 线程关闭
         *  shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
         *   shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
         */
        public void destroy() {
            if (mThreadPoolExecutor != null) {
                try {
                    mThreadPoolExecutor.shutdown();
                    // (所有的任务都结束的时候,返回TRUE)
                    if (!mThreadPoolExecutor.awaitTermination(1000L, TimeUnit.MILLISECONDS)) {
                        // 超时的时候向线程池中所有的线程发出中断(interrupted)。
                        mThreadPoolExecutor.shutdownNow();
                    }
                } catch (InterruptedException e) {
                    // awaitTermination方法被中断的时候也中止线程池中全部的线程的执行。
                    mThreadPoolExecutor.shutdownNow();
                }
            }
        }


    }

}

Timer定时器 

 

           //只执行一次
         public void schedule(TimerTask task, long delay);
         public void schedule(TimerTask task, Date time);
   
          //循环执行
          // 在循环执行类别中根据循环时间间隔又可以分为两类
         public void schedule(TimerTask task, long delay, long period) ;
         public void schedule(TimerTask task, Date firstTime, long period) ;
    
         public void scheduleAtFixedRate(TimerTask task, long delay, long period)
         public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

           1、schedule,如果第一次执行被延时(delay),
         *      随后的任务执行时间将以上一次任务实际执行完成的时间为准
         *  2、scheduleAtFixedRate,如果第一次执行被延时(delay),
         *      随后的任务执行时间将以上一次任务开始执行的时间为准(需考虑同步)

取消定时器

  private void stopTimer(){  
        if (mTimer != null) {  
            mTimer.cancel();  
            mTimer = null;  
        }  
        if (mTimerTask != null) {  
            mTimerTask.cancel();  
            mTimerTask = null;  
        }     
        count = 0;  
    }  

 

 

线程同步

同步关键字synchronized    

1.同步方法 
    即有synchronized关键字修饰的方法。 
    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 
    内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

    代码如: 
    public synchronized void save(){}

   注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

2.同步代码块 
    即有synchronized关键字修饰的语句块。 
    被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

    代码如: 
    synchronized(object){ 
    }

 

使用特殊域变量(volatile)实现线程同步

    a.volatile关键字为域变量的访问提供了一种免锁机制, 
    b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新, 
    c.因此每次使用该域就要重新计算,而不是使用寄存器中的值 
    d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 
        例如: 
        在上面的例子当中,只需在account前面加上volatile修饰,即可实现线程同步。 
    
    代码实例:     

 

      //只给出要修改的代码,其余代码与上同
        class Bank {
            //需要同步的变量加上volatile
            private volatile int account = 100;

            public int getAccount() {
                return account;
            }
            //这里不再需要synchronized 
            public void save(int money) {
                account += money;
            }
        }

复制代码

 

使用重入锁实现线程同步

    在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。 
    ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
    它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力


    ReenreantLock类的常用方法有:

        ReentrantLock() : 创建一个ReentrantLock实例 
        lock() : 获得锁 
        unlock() : 释放锁 
    注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 
        
    例如: 
        在上面例子的基础上,改写后的代码为: 
        
    代码实例: 

 

//只给出要修改的代码,其余代码与上同
        class Bank {
            
            private int account = 100;
            //需要声明这个锁
            private Lock lock = new ReentrantLock();
            public int getAccount() {
                return account;
            }
            //这里不再需要synchronized 
            public void save(int money) {
                lock.lock();
                try{
                    account += money;
                }finally{
                    lock.unlock();
                }
                
            }
        }

https://www.cnblogs.com/XHJT/p/3897440.html

 

ThreadLocal

      ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据。那么ThreadLocal是如何做到为每一个线程维护一份独立的变量副本的呢

原理:

每个Thread的对象都有一个ThreadLocalMap,当创建一个ThreadLocal的时候,就会将该ThreadLocal对象添加到该Map中,其中键就是ThreadLocal,值可以是任意类型。

在该类中,我觉得最重要的方法就是两个:set()和get()方法。当调用ThreadLocal的get()方法的时候,会先找到当前线程的ThreadLocalMap,然后再找到对应的值。set()方法也是一样。


public class MainActivity extends AppCompatActivity {
    private ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<Integer>();
    private String TAG = this.getClass().getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG, "[Thread--main] 初始值integerThreadLocal=" + integerThreadLocal.get());
        Log.e(TAG, "[Thread--main] 设置integerThreadLocal=0");
        integerThreadLocal.set(0);
        Log.e(TAG, "[Thread--main] 获取get值integerThreadLocal=" + integerThreadLocal.get());

        new Thread("Thread--1") {
            @Override
            public void run() {
                Log.e(TAG, "[Thread--1] 初始值integerThreadLocal=" + integerThreadLocal.get());
                Log.e(TAG, "[Thread--1] 设置integerThreadLocal=1");
                integerThreadLocal.set(1);
                Log.e(TAG, "[Thread--1] 获取get值integerThreadLocal=" + integerThreadLocal.get());
            }
        }.start();


        new Thread("Thread--2") {
            @Override
            public void run() {
                Log.e(TAG, "[Thread--2] 初始值integerThreadLocal=" + integerThreadLocal.get());
                Log.e(TAG, "[Thread--2] 设置integerThreadLocal=2");
                integerThreadLocal.set(2);
                Log.e(TAG, "[Thread--2] 获取get值integerThreadLocal=" + integerThreadLocal.get());
            }
        }.start();
    }


}


//打印
 E/MainActivity: [Thread--main] 初始值integerThreadLocal=null
    [Thread--main] 设置integerThreadLocal=0
    [Thread--main] 获取get值integerThreadLocal=0
E/MainActivity: [Thread--1] 初始值integerThreadLocal=null
    [Thread--1] 设置integerThreadLocal=1
    [Thread--1] 获取get值integerThreadLocal=1
 E/MainActivity: [Thread--2] 初始值integerThreadLocal=null
    [Thread--2] 设置integerThreadLocal=2
    [Thread--2] 获取get值integerThreadLocal=2

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值