从操作系统的角度讲,线程间通信比进程间通信要容易的多,因为线程之间可以共享进程的内存空间。因此,他们可以共享位于进程全局数据区和栈和堆上的所有内容。
唯一只属于某个线程的就是线程的栈-------它可以存放只属于线程的对象。
下面逐一解读线程间通信方式:
1. 共享进程的变量
这是最基本的通信方式,但要注意不要共享线程栈上的变量,因为它随时可能被某个线程销毁,而另一个线程就无法访问它了。
所以Java编译器不允许使用栈上的变量来共享。
例子1:
如下面这个编译器是会报错的,
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int i=0;
Thread a=newThread(new Runnable(){
@Override
public voidrun() {
// TODOAuto-generated method stub
i++;
}
});
}
上面的自动变量i可以看做是进程的变量,但它有可能被申请它的线程销毁,因为无法用来进行共享。
例子2:
正面的例子比如android中的handler,它是需要在进程空间共享的。
2. TLS(Thread Local Storage)
线程本地存储,本质上是存储一系列线程号和Looper对象的key-value键值对。
比如Android的Looper
public finalclass Looper {
privatestatic final String TAG = "Looper";
// sThreadLocal.get() will return null unlessyou've called prepare().
static final ThreadLocal<Looper>sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; //guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
}
Looper有一个静态的
static final ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();
ThreadLocal本质上是一系列线程号和Looper对象的key-value键值对,因为sThreadLocal是静态的,所以它为所有的线程所共享。
而sThreadLocal.get()就是获取当前线程对应的Looper。
例子:
起一个Worker线程来做事情
private static class Worker implementsRunnable {
……
publicvoid run() {
synchronized(mLock) {
Looper.prepare();
mLooper= Looper.myLooper();
mLock.notifyAll();
}
Looper.loop();
}
publicvoid quit() {
mLooper.quit();
}
}
其中Looper.prepare()就是重新创建一个Looper,查看Looper源码的话,就调用了
sThreadLocal.set(new Looper(quitAllowed));
也就是往sThreadLocal插入了一个键值对。
另外一个Looper有一个MessageQueue,用来存储Message。
在Looper和Handler两者中,Looper实现了线程间通信,Handler是对Looper的封装,是Looper的友好接口,方便用户调用而已。而且Handler在各个线程间共享,以达到多线程通信的目的。
3. 并发,同步和互斥(Java)
3.1 Synchronize关键字
这个是monitor,保证互斥的,一块代码不能同时被两个线程访问。
3.2 Semaphore类
Java中的Semaphore类,是进行并发控制的,也就是说,它可以限制访问一个资源(或代码块)的线程数目。当设定的线程数目是1时,并发其实就退化到了互斥。
3.3 Lock类
Lock类也可以取代Object的Notify和Wait
3.4 对象锁
Synchronized+Object的Notify和wait,这三个一起构成了同步。
比如下面这段程序,保证了Thread A和Thread B是交替执行的。
例子:
public void onClick_start_thread_a(View v) {
logger.d("onClick_start_thread_a");
Runnable r = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (flag) {
System.out.println("Thread A!");
flag.notifyAll();
try
{
flag.wait();
} catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
};
Thread t = new Thread(r);
t.start();
}
public voidonClick_start_thread_b(View v) {
logger.d("onClick_start_thread_b");
Runnable r = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (flag) {
System.out.println("Thread B!");
flag.notifyAll();
try
{
flag.wait();
} catch (InterruptedExceptione)
{
e.printStackTrace();
}
}
}
}
};
Thread t = new Thread(r);
t.start();
}
附:
下面附上一段使用Handler,Looper的代码
private static class Worker implementsRunnable {
privatefinal Object mLock = new Object();
privateLooper mLooper;
/**
* Createsa worker thread with the given name. The thread
* thenruns a {@link android.os.Looper}.
* @paramname A name for the new thread
*/
Worker(Stringname) {
Threadt = new Thread(null, this, name);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
synchronized(mLock) {
while(mLooper == null) {
try {
mLock.wait();
} catch (InterruptedException ex) {
}
}
}
}
publicLooper getLooper() {
returnmLooper;
}
publicvoid run() {
synchronized(mLock) {
Looper.prepare();
mLooper= Looper.myLooper();
mLock.notifyAll();
}
Looper.loop();
}
publicvoid quit() {
mLooper.quit();
}
}
package com.example.test;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
public classProgressTestActivity extends Activity {
privateProgressBar progress;
private TextView text;
private Worker mWorker;
privateWorkerHandler mWorkerHandler;
private UIHandlermUIHandler;
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress =(ProgressBar) findViewById(R.id.progressBar1);
text =(TextView) findViewById(R.id.textView1);
mWorker = new Worker("artworker");
mWorkerHandler = newWorkerHandler(mWorker.getLooper());
mUIHandler = newUIHandler(Looper.myLooper());
}
public voidstartProgress(View view) {
Message msgObj = mWorkerHandler.obtainMessage();
msgObj.what = 2;
mWorkerHandler.sendMessage(msgObj);
}
// Simulatingsomething timeconsuming
private voiddoFakeWork() {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
private static class Worker implements Runnable{
private final Object mLock = new Object();
private Looper mLooper;
/**
* Creates a worker thread with the given name.The thread then runs a
* {@link android.os.Looper}.
*
* @param name
* A name for the new thread
*/
Worker(String name) {
Thread t = new Thread(null, this, name);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
synchronized (mLock) {
while (mLooper == null) {
try {
mLock.wait();
} catch(InterruptedException ex) {
}
}
}
}
public LoopergetLooper() {
return mLooper;
}
public void run() {
synchronized (mLock) {
Looper.prepare();
mLooper = Looper.myLooper();
mLock.notifyAll();
}
Looper.loop();
}
public void quit(){
mLooper.quit();
}
}
public class UIHandlerextends Handler {
private long mAlbumId = -1;
public UIHandler(Looperlooper) {
super(looper);
}
@Override
public voidhandleMessage(Message msg) {
if (msg.what == 1) {
int value =msg.getData().getInt("value");
progress.setProgress(value);
MessagemsgObj = mWorkerHandler.obtainMessage();
msgObj.what = 2;
mWorkerHandler.sendMessage(msgObj);
}
}
}
public classWorkerHandler extends Handler {
private int value = 0;
public WorkerHandler(Looperlooper) {
super(looper);
}
@Override
public voidhandleMessage(Message msg) {
if (msg.what == 2) {
doFakeWork();
if (value == 10)
value = 0;
MessagemsgObj = mUIHandler.obtainMessage();
msgObj.what = 1;
Bundle b = new Bundle();
b.putInt("value", value++);
msgObj.setData(b);
mUIHandler.sendMessage(msgObj);
}
}
}
}