如图中:A和C, synchronized 关键字加在方法外,那么他们就会共享一个线程锁(及这个对象),不管是执行A还是C方法都要,等之前的A或C方法执行完毕。
如图中:B , synchronized 关键字加在方法内的代码块上,那么小括号中的参数(及红色的成员变量)就是识别是否同步的标示,也就是说‘那些要执行synchronized代码块的参数一致的线程,会进行排队等候。’
凡是会被线程共享的都需要被保护(只读的不算)。
一旦决定做保护,就要在所有地方加保护。
thread.start(); 开启线程。
thread.stop(); 结束线程。(不建议使用,造成的后果不可预知)。
thread.interrupt(); 打断线程。代替stop方法,
thread.interrupt()实际上是 给线程进行 线程中断的标记,实际上没有打断。
那么到底如何安全的结束线程呢?
之前使用thread.interrupt()对线程进行了标记
1 在需要打断的地方 使用if(thread.isInterrupted())~~配合 return;
2 在需要打断的地方 使用if(Thread.Interrupted())~~配合 return; 和上面的区别是,当标记为true时变成false ,为false时还是 false;
Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i <1_000_000 ; i++) { if (Thread.interrupted()){ //执行打断线程的收尾工作 return; } } } });
new Thread(){ @Override public void run() { try { sleep(2000); } catch (InterruptedException e) { //主动打断后的处理 e.printStackTrace(); }
InterruptedException 一定是在你主动调用
thread.interrupt()后才会触发
例如在一个线程睡眠时,想要打断睡眠,就可以主动调用 thread.interrupt() 这样就会触发 InterruptedException。
扩展 SystemClock.sleep(2000); 安卓中的睡眠不用抛异常
场景:比如 等待初始化完毕在进行下一步。
private String testString; private synchronized void printString(){ while(testString==null){ try { wait(33); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("String:"+testString); } private synchronized void initString(){ testString = "zhangyuge"; notify();// notifyAll(); }
表示 threadA 想停止自己等待 threadB 完成后在执行自己
threadA = new Thread() { run{ threadB.join } }
表示在同等优先级的线程间 稍稍让一下(自己停一下,让别人先执行)
ThreadLocal threadnumber;
threadnumber 的类型取决于 泛型中的类型;
new Thread(){ @Override public void run() { threadnumber.set(1) threadnumber.get() // 1 } } new Thread(){ @Override public void run() { threadnumber.set(2) threadnumber.get() // 2 } }
在两个线程中 threadnumber.set get的值都互不干涉。原理类似与一个 Map存取值。
HandlerThread
run 方法
looper.prepare();//创建并保存 Looper对象
looper.loop();//启动循环(检查和执行任务/ 消息)
Looper
循环
3.Handler
添加消息、制定消息的助理方案
如何判断一个对象是否 应该被回收呢?
不是看 这个对象有多少引用,而是看这个对象是否有来自 GarBage Collector Root 直接或间接的指向,有的话不会被回收。
什么是GC ROOT呢 (分三类)
静态对象
运行中的线程
本地的对象
AsyncTask 之所以会内存泄露,并不是因为AsyncTask 特殊。
比如说一个Activity 中 new Thread 做while 循环打印,当activity退出时,thread 会持一直持有他的引用, 导致内存泄露。
所以导致内存泄露的是线程没处理好,那么在AsyncTask 中导致内存泄露也是因为【线程】。
结论: 使用 AsyncTask 或者线程 快速结束就没问题,只要使用线程就记得要将他关闭。
Executors 方便了我们使用线程池。
同Executors 拿到线程池 有4中方法;
newFixedThreadPool()
该方法返回一个固定线程数量的线程池,该线程池中的线程数量始终不变,即不会再创建新的线程,也不会销毁已经创建好的线程,自始自终都是那几个固定的线程在工作,所以该线程池可以控制线程的最大并发数。 超出的线程会在队列中等待。
newCachedThreadPool()
该方法返回一个可以根据实际情况调整线程池中线程的数量的线程池。如果没有线程不够用则会一直创建,有空闲线程则会复用。
newSingleThreadExecutor()
顾名思义,返回只有一个线程的线程池。多余的任务会存在队列中等待执行
newScheduledThreadPool()
返回一个可以固定线程个数和设置线程延迟执行时间,执行周期 的线程池
好了,来看下具体使用方式:
第一种的代码
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3); executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { Log.i("thread", Thread.currentThread().getName()); } }, 5000,3000, TimeUnit.MILLISECONDS);
第四种的代码
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3); executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { Log.i("thread", Thread.currentThread().getName()); } }, 5000,3000, TimeUnit.MILLISECONDS);