Java中的线程
1. 线程的两种实现方式
①继承Thread类
②实现Runnable接口
两者区别在于,Thread这个类的对象,代表的是一个线程,而Runnable的对象,代表的是线程体(也就是线程要执行的代码)。
2.线程的生命周期
创建---调用start()进入就绪状态---抢占到CPU就开始进入运行状态---运行过程中被别的线程抢到CPU,或者遇到阻塞,则进入就绪状态---如果执行完线程体,则进入死亡状态
线程死亡之后,不可能再复活。
3.多线程同步
如果多个线程访问同一个资源,会产生多个线程竞争一个资源,则会产生多线程错误,这时需要通过同步方式来解决,使用synchronized关键字,采用同步代码块或者同步方法。
所谓的同步,就是指在一个线程访问资源时,别的线程是无法访问这个资源的。
MainThread和WorkerThread
Android中可以将线程分为:MainThread和WorkerThread两大类
MainThread就是主线程,又称为UI线程,所有和UI相关的代码,都是运行在MainThread中的。
除了MainThread之外的线程,都是WorkerThread,原则上来讲WorkerThread是不允许操作UI组件的。
Android当中线程的使用
实现一个demo,要求实现点击按钮5秒钟之后,改变TextView的文字。

package cn.lixyz.handlertest; import android.app.Activity; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private TextView textView; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(){ @Override public void run() { super.run(); try { sleep(5000); textView.setText("改变之后的文字"); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } }); } }

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" android:text="@string/hello_world" android:textSize="50dp" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" android:text="点击我改变文字" /> </LinearLayout>
像上面一样编码的话,点击按钮5秒之后,会提示错误:
并抛出异常:
09-15 03:28:33.964 5854-6002/cn.lixyz.handlertest E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-112 Process: cn.lixyz.handlertest, PID: 5854 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:820) ......
上面的代码和异常证明了,Android是不允许非UI线程去修改UI组件的。
但是也有例外,譬如ProgressBar,看代码

package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; public class MainActivity extends Activity { private ProgressBar progressBar; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar = (ProgressBar) findViewById(R.id.progressBar); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread() { @Override public void run() { super.run(); for (int i = 0; i < 100; i++) { try { sleep(100); progressBar.setProgress(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } }); } }

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <ProgressBar android:id="@+id/progressBar" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" android:text="点击开始加载" /> </LinearLayout>
运行结果:
所以说:大多数情况下,在WorkerThread中是无法修改UI的,只有少数情况下才可以。
那么可以不可以把所有修改UI的代码全部放在MainThread中执行呢?答案是否定的。
在一个应用程序之中,主线程通常用于接收用户的输入,以及将运算的结果反馈给用户,后台运行耗时代码则会导致主线程阻塞,程序无法相应,也就是常见的ANR(application not responding),应用程序没有相应。
所以说,对于一些可能产生阻塞的操作,必须放到WorkerThread中,这时候就产生了WorkerThread和MainThread的通信问题。