NO.2 Android 线程间交互
零蚀
线程的终止
-
一个线程终止另一个线程
Thread thread=new Thread(new Runnable() { @Override public void run() { } }); thread.start(); thread.stop();
线程里 有一个非常有效的终止线程的方法,可以使用stop来有效的结束一个线程,但是这个api在4.1的时候就已经被弃用了,因为结果是不可预期的,当结束线程时候,不能了解到线程所做的工作是什么,所以对这种不可控的因素,是不可靠的。
Thread thread=new Thread(){ @Override public void run() { //重置interrupt的状态 if(Thread.interrupted()){ // 收尾 return; } // 下面的方法不会改变interrupt标记的状态 //if(isInterrupted()){ // return; //} } }; thread.start(); thread.interrupt();
interrupt方法并非像stop即死,它是给这个线程做个中断标记。通知线程将被中断。如果线程在合适的位置进行终止,如上述代码。
-
Thread.sleep
try { Thread.sleep(100); } catch (InterruptedException e) { // InterruptedException监测到状态为true则抛异常 e.printStackTrace(); }
在睡眠时候加上这个异常,是为了防止线程睡眠状态过好,而当interrupt状态发生改变,那么睡眠就结束了,进入异常阶段,而InterruptedException也会将interrupt状态进行重置,所以如果需要关闭外部耗/循环时操作,需要return!这sleep即用来睡眠也用来被打断。。
SystemClock.sleep(1000);
这也是睡眠操作,但是他不会抛异常,也就是不接受打断,他只是睡,雷打不醒的那种。
-
wait & notify
wait & notify 是运行在synchornized里面的,并对其产生作用。
public synchronized void init_name(){ name = "无所不知的神棍"; } public synchronized void print_name(){ while(name ==null){ } System.out.println(name); } new Thread(){ @Override public void run() { SystemClock.sleep(1000); init_name(); } }.start(); new Thread(){ @Override public void run() { SystemClock.sleep(500); print_name(); } }.start();
上述方法会出现死锁情况,
处理方式:
public synchronized void init_name(){ name = "无所不知的神棍"; notify(); // notifyAll(); } public synchronized void print_name(){ while(name ==null){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name); }
在此interrupt也会唤醒wait,由于wait不清楚是被谁唤醒的,所以wait之前必须要加while循环♻️。wait()& notify() 不是Thread的方法,是object方法,他的作用对象或说是依附对象是monitor,是通过monitor来规定线程们的wait行为,所以所处位置必须是object的方法。
-
Thread.join()
join()的方法和python的方法一致,当thread1.join后先执行thread1线程的内容才会执行thread2后续的方法。
final Thread thread1=new Thread(){ @Override public void run() { super.run(); } }; thread1.start(); Thread thread2=new Thread(){ @Override public void run() { try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }; thread2.start();
-
Thread.yield()
yield 方法也和python一致,yield是将自己的时间片让出去,让其他线程执行完毕之后才会执行。
Thread thread2=new Thread(){ @Override public void run() { //.... Thread.yield(); // ... } }; thread2.start();
Handler机制
-
handler用法
handler作用于指定中的运行中线程的代码进行操作。
// handler默认操作(post)的是new Handler的线程,当然我们也可以定义handler操作的对象 // new Handler(Looper.getMainLooper()); Handler handler=new Handler(); handler.post(new Runnable() { @Override public void run() { // 将内容推向主线程 } });
handler中设置了task,loop则是对task.run进行操作管理,这里的post是将内容推入Queue中,由MessageQueue这个链表队列。
-
ThreadLocal
ThreadLocal是针对线程本地的高速缓存的变量设置,这种设置互不影响,比如以下案例,每个线程的设置获取都不会影响到其他线程的使用。
final ThreadLocal<Integer> age = new ThreadLocal<>(); new Thread(){ @Override public void run() { age.set(10); age.get(); } }.start(); new Thread(){ @Override public void run() { age.set(20); age.get(); } }.start();
-
Looper
源码
// HandlerThread @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
- 这里的Looper.prepare() 是创建了一个loop完成其初始化工作
- Looper.myLooper()指定了当前执行的线程
- Looper.loop()是反复while ture loop其中的task任务。
loop()源码
public static void loop() { ... for (;;) { ... // 分发消息,这里调用的是handler的dispatchMessage() msg.target.dispatchMessage(msg); // dispatchMessage源码中,如果一旦拿到了message则,callback信息的内容。 ... ... }
内存泄漏
new NewAsyncTask().execute(10,10,10);
class NewAsyncTask extends AsyncTask<Integer,Integer,String>{
@Override
protected String doInBackground(Integer... integers) {
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
AsyncTask在activity里定义会持有Activity的引用,但不一定导致不能被回收,垃圾回收机制在判定一个模块是否可以被回收并非是看它有没有引用的指向,这是不可靠的,而是查看它是否含有gc root相关联的引用,如果是含有相关联的引用,则判定他是不可被垃圾回收器回收的内容。
- 第一种是运行中的线程就具有gc root,所以在asynctask在运行时调用的thread导致它含有gc root,容易导致内存泄漏,无法释放。
- 第二种是static,他是含有gc root的。
- JNI方法的local变量或参数;全局JNI引用;用于同步的监控对象
以上便是导致内存泄漏的根源。在页面关闭之后如果AsyncTask还运行了一段时间,其实没有什么影响,和软引用,弱引用已经没有太大的关系。如果很长时间,就不要放在activity中了。
来源:CSDN
作者:零蚀zero eclipse
链接:https://blog.csdn.net/qq_38315348/article/details/104576819