3. Managing the lifecycle of a Basic Thread
2017-07-25 11:11
399 查看
1. Basics
Lifecycle
可以在Thread.State类中查看Thread的状态。New
在Thread执行之前,Thread对象被创建。这个实例不会建立执行环境。默认Thread构造方法分配新创建的Thread的优先级和所属的Thread Group与创建这个新Thread所在的线程是相同的(The default construction assigns the newly created thread to the same thread group as the thread that is doing the creation, with the same priority)。例如,在UI Thread中创建新的Thread,那么这个新创建的Thread和UI Thread所属同一个Thread Group和Priority。Runnable
当Thread.start()方法被调用,这个执行环境被建立并且这个Thread开始准备执行。当调度器选择了这个Thread执行,那么这个run()方法会被调用,任务开始被执行。Blocked/Waiting
被动当Thread需要等待资源时,执行能被中止。
主动
调用Thread.sleep();
调用Thread.yield():Thread放弃执行,让调度器重新选择哪个Thread执行。这个调度器能自由的选择哪个线程执行,调度器可能还会选择这个Thread执行。
Terminated
当run()方法执行完毕,这个Thread就会终止并释放它占用的资源。这个Thread不会被服用,Thread的建立和销毁是很重的操作,如果需要多次这样操作的话,请使用Thread Pool(线程池)。Interruptions
Thread能被interrupted,这个请求Thread应该终止,interrupt是由Thread自己决定的。Thread t = new SimpleThread(); t.start(); // 开始线程 t.interrupt(); // 请求interruption
Thread自己能调用interrupt,其他Thread也可以调用interrupt这个Thread。发布一个Interruption不会直接的影响Thread的执行,它仅仅是设置了Thread内部的interrupted flag为interrupted。这个Interrupted Thread要检查这个interrupted flag,然后优雅地终止。Thread必须要实现Cancellation Point来允许这个Thread被interrupted并终止:
public class SimpleThread extends Thread { @Override public void run() { // 通过使用isInterrupted()方法检查interrupt flag来实现Cancellation Point while (isInterrupted() == false) { // Thread 运行 } // 任务结束,Thread终止 } }
如果Thread被interrupted会抛出一个InterruptedException的异常。当InterruptedException被抛出后,这个Thread中的interrupted flag就会被重置 – 例如,即使这个Thread已经interrupted,isInterrupted()方法返回false。
相关方法
interrupt():请求线程interrupt;isInterrupted():检查线程是否interrupted,当InterruptedException抛出后,interrupted flag会被重置,变为false。
static Thread.interrupted():这个是静态方法,也是检查线程是否interrupted,但是这个方法会清理interrupted flag。
Uncaught Exceptions
如果Thread异常结束,可能抛出unchecked exception。Unchecked exception是RuntimeException的子类,它们不能被try/catch捕获。为了防止unchecked exception不能捕获而不能给通知,我们可以给Thread设置一个UncaughtExceptionHandler,这个UncaughtExceptionHandler在Thread终止前会被调用。我们可以在这个UncaughtException中优雅地终止Thread或者给出提示信息。我们可以通过方法设置全局Thread的ExceptionHandler,也可以设置某个thread的ExceptionHandler,Thread设置的本地ExceptionHandler的调用优先级比全局的ExceptionHandler高:
Unhandled Exceptions on the UI Thread
在Application开启时,Android绑定了一个全局的UncaughtExceptionHandler给这个Application。默认情况这个exception handler绑定了Application中的所用Thread,它对待所有Thread的unhandled exception是一样的:杀死这个进程。可以参考Android Source Code中的RuntimeInit.java文件(链接:https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/os/RuntimeInit.java)
(RuntimeInit.java的修改记录:https://android.googlesource.com/platform/frameworks/base/+log/master/core/java/com/android/internal/os/RuntimeInit.java
SHA1号addbf90的修改:https://github.com/android/platform_frameworks_base/commit/addbf9015a65ed7704a4fc22f36380dd153698da)
public class RuntimeInit { ... ... // Application的UncaughtExceptionHandler private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler { ... ... } protected static final void commonInit() { ... ... // 设置UncaughtExceptionHandler Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler()); ... ... } }
设置自己Application的UncaughtExceptionHandler:
// 设置Application自己全局的UncaughtExceptionHandler Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler()); private static class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private final Thread.UncaughtExceptionHandler defaultHandler; public CustomUncaughtExceptionHandler() { // 获取此Application默认的UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); } @Override public void uncaughtException(Thread thread, Throwable throwable) { // TODO 做一些自定义的操作 Log.i(TAG, "### This is my custom uncaught exception handler ###"); // 使用Thread default uncaught exception handler的变量调用uncaughtException,使得Application接收到unchecked exception时杀掉进程 defaultHandler.uncaughtException(thread, throwable); } }
2. Thread Management
Definition and Start
使用简单地例子来说明定义Thread,例子中有一个外部类(Outer Class) AnyObject,定义一个方法anyMethod()来start Thread,此方法在UI Thread中调用。Annoymous inner class
使用匿名内部类的方法来定义并开启Thread代码是很简单的,但是匿名内部类会保留外部类的引用,而导致外部类的引用在Thread结束之前不能被回收。像anyMethod()方法在UiThread中调用,使得context不能及时释放,会使内存占用大,可能会内存溢出。public class AnyObject { @UiThread public void anyMethod() { new Thread() { public void run() { doLongRunningTask(); } }.start(); } }
Public Thread
把Thread定义在一个单独的类中,这样Thread就不会保留外部类AnyObject的引用了,但是这样会增加类文件数量。class MyThread extends Thread { public void run() { doLongRunningTask(); } } public class AnyObject { private MyThread myThread; @UiThread public void anyThread() { myThread = new MyThread(); myThread.start(); } }
Static inner class thread definition
使用静态内部类的方式来定义Thread。静态内部类仅仅会保留外部类AnyObject中类对象的引用,而不会保留实例对象的引用。因此,外部类AnyObject中的实例对象内存回收不受静态内部类影响。推荐使用这种方式定义Thread。
public class AnyObject { static class MyThread extends Thread { public void run() { doLongRunningTask(); } } private MyThread myThread; @UiThread public void anyMethod() { myThread = new MyThread(); myThread.start(); } }
Summary
上面三种方式中最好使用静态内部类的方式定义Thread,但是上面的例子中Thread是直接使用new Thread();创建的,这样的Thread的是不好控制的(Thread的数量,以及Thread不能回收利用等等),我们可以使用Thread Pool(线程池)或者HandlerThread来创建,它们能控制Thread执行的数量。Retention(保留/滞留)
Thread的生命周期不受Android Component的生命周期应用。例如在Activity中创建一个Thread来处理耗时操作,如果Activity的configuration改变了(如旋转屏幕),那么创建Thread的Activity就被销毁了,这样Thread处理的数据结果就没法返回到configuration改变后新创建的Activity中,为了处理这种情况我们需要保留Thread,即把Thread绑定到configuration改变后新创建的Activity。
因为在Android API 13之后有了Fragment,因此保留Thread的方式在Activity和Fragment中不同。
Retaining a thread in an Activity
Activity中相关的方法:public class ThreadRetainActivity extends Activity { private static final String TAG = ThreadRetainActivity.class.getSimpleName(); private TextView retainThreadBeforeText = null; private TextView retainThreadAfterText = null; private Button retainThreadButton = null; private MyThread myThread = null; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_retainthread); Log.i(TAG, "ThreadRetainActivity # UIThread: " + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); retainThreadBeforeText = (TextView) findViewById(R.id.retain_thread_before_text); retainThreadAfterText = (TextView) findViewById(R.id.retain_thread_after_text); retainThreadButton = (Button) findViewById(R.id.retain_thread_btn); // If there is a retained thread object, it is restored. The new Activity instance is // registered to the thread. Object retainObject = getLastNonConfigurationInstance(); if (retainObject != null) { myThread = (MyThread) retainObject; myThread.attach(this); // 当activity的configuration改变后(如转屏),把Thread绑定到新建的Activity } retainThreadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { myThread = new MyThread(ThreadRetainActivity.this); myThread.start(); retainThreadBeforeText.setText(myThread.getId() + " - " + myThread.getName()); } }); } @Override public Object onRetainNonConfigurationInstance() { // 当activity configuration改变后(转屏),若此Activity创建的Thread还运行的话,把此Thread保留下来,然后绑定到新建的Activity上 if (myThread != null && myThread.isAlive()) { return myThread; } return null; } // 实现静态内部类模拟处理耗时操作 private static class MyThread extends Thread { private WeakReference<ThreadRetainActivity> activity = null; public MyThread(ThreadRetainActivity activity) { this.activity = new WeakReference<ThreadRetainActivity>(activity); } private void attach(ThreadRetainActivity activity) { this.activity = new WeakReference<ThreadRetainActivity>(activity); } @Override public void run() { super.run(); final String text = getTextFromNetwork(); if (activity.get() != null) { Log.i(TAG, "ThreadRetainActivity # MyThread # run: " + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); activity.get().retainThreadAfterText.setText(text + Thread.currentThread().getId() + " - " + Thread.currentThread().getName()); } } // simulate long operation private String getTextFromNetwork() { SystemClock.sleep(5000); Log.i(TAG, "ThreadRetainActivity # MyThread # getTextFromNetwork"); return "Text is from network. "; } } }
Retaining a thread in an Fragment
Fragment是添加到Activity中使用的。在Fragment中,保留它里面的Thread或者其他State,那么直接在Fragment.onCreate()方法中调用setRetainInstance(true);即可。这样当Activity的configuration改变时,这个Fragment就会保留。ThreadFragment.java
public class ThreadFragment extends Fragment { private static final String TAG = ThreadFragment.class.getSimpleName(); private ThreadRetainWithFragmentActivity activity = null; private MyFragmentThread myFragmentThread = null; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 当Activity的configuration改变时,保留Fragment setRetainInstance(true); } @Override public void onAttach(Context context) { super.onAttach(context); // 绑定到Activity上 activity = (ThreadRetainWithFragmentActivity) context; } @Override public void onDetach() { super.onDetach(); // 解除绑定 activity = null; } public void execute() { myFragmentThread = new MyFragmentThread(activity); myFragmentThread.start(); } private static class MyFragmentThread extends Thread { private WeakReference<ThreadRetainWithFragmentActivity> weakActivity = null; public MyFragmentThread(ThreadRetainWithFragmentActivity activity) { weakActivity = new WeakReference<ThreadRetainWithFragmentActivity>(activity); } @Override public void run() { super.run(); String text = getTextFromNetwork(); if (weakActivity != null) { weakActivity.get().setText(text); } } // simulate long operation private String getTextFromNetwork() { SystemClock.sleep(5000); Log.i(TAG, "ThreadFragment # MyFragmentThread # getTextFromNetwork"); return "Text is from network. "; } } }
ThreadRetainWithFragmentActivity.java
public class ThreadRetainWithFragmentActivity extends Activity { private ThreadFragment threadFragment = null; private Button retainFragmentBtn = null; private TextView retainFragmentText = null; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_retain_fragment_thread); retainFragmentBtn = (Button) findViewById(R.id.retain_fragment_thread_btn); retainFragmentText = (TextView) findViewById(R.id.retain_fragment_thread_text); FragmentManager fm = getFragmentManager(); threadFragment = (ThreadFragment) fm.findFragmentByTag("fragmentthread"); if (threadFragment == null) { FragmentTransaction ft = fm.beginTransaction(); threadFragment = new ThreadFragment(); ft.add(threadFragment, "fragmentthread"); ft.commit(); } retainFragmentBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 启动Fragment中的Thread threadFragment.execute(); } }); } public void setText(String content) { retainFragmentText.setText(content); } }
3. Avoiding Memory Leaks
Use Static Inner Classes
Use Weak References
使用静态内部类定义Thread,如果Thread内部需要访问外部类的变量/方法时,使用弱应用的方式来实现。Stop Worker Thread Execution
Retain Worker Threads
参考 Retaining a thread in an Activity 和 Retaining a thread in an FragmentClean Up the Message Queue
相关方法:removeCallbacks(Runnable r) removeCallbacks(Runnable r, Object token) removeCallbacksAndMessages(Object token) removeMessaegs(int what) removeMessages(int what, Object object)
相关文章推荐
- Some tips about the life cycle of Maya thread pool
- The Life Cycle of a Servlet
- How to invoke the method of managed bean and render view in JSF when we are outside the lifecycle of JSF
- The Life Cycle of a JSP Page
- Managing the Lifecycle of a Bound Service
- The ASP.NET Page Lifecycle – A Basic Approach
- DOJO组件生命周期(the life cycle of dojo widget)
- 【Java多线程】之四:Life Cycle of Thread
- Life Cycle of the Flex UIComponent Base Class
- DOJO组件生命周期(the life cycle of dojo widget)
- What are the phases of the maven default lifecycle?
- What are the phases of the maven default lifecycle?
- What events are fired as part of the ASP.NET System.Web.UI.Page lifecycle?
- Managing the Lifecycle of a Service
- 视图控制器生命周期中各个重要的方法(Swift) (Important Methods during the Lifecycle of a View Controller)
- Business analysis and SOA part 4 of 6: SOA delivery lifecycle and the top-down approach [by Thomas Erl]
- Spring in Action 3 - the startup lifecycle of a typical bean
- The Lifecycle and Cascade of WeChat Social Messaging Groups-www2016-20160512
- The Make or Break Role of Information Lifecycle Management @ JDJ
- A journey on the Android Main Thread - Lifecycle b