线程间通信原理

从操作系统的角度讲,线程间通信比进程间通信要容易的多,因为线程之间可以共享进程的内存空间。因此,他们可以共享位于进程全局数据区和栈和堆上的所有内容。

唯一只属于某个线程的就是线程的-------它可以存放只属于线程的对象。

下面逐一解读线程间通信方式:

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);
            }
        }
    }
}
 


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。