[Go Back]
1.4.2 Thread造形与Activity造形的美丽组合
复习Thread框架造形
前面介绍过了Thread框架,也就是{Thread, Runnable, <T>}造形。如下图所示:

图1-20 框架设计师眼中的Thread机制
基于这个Runnable接口,Thread基类就能诞生一个新线程,并透过Runnable接口去调用子类别的run()函数。如下图所示:

图1-21 Thread框架的元素互动情形
这个Thread类别扮演引擎角色,Runnable是轮盘接口,而Task则是轮胎。在Thread的start()函数会诞生一个小线程,反向调用Task的run()函数;必要时,Task会正向调用Thread的currentThread()等函数。
换句话说,Runnable扮演<I>的角色,Thread扮演<E>的角色,而Task扮演<T>的角色。Thread引擎透过Runnable接口,调用了Task的run()等函数。我们称之为{Thread, Runnable, <T>}造形,或称为:Thread框架造形。[歡迎光臨 高煥堂 網頁:http://www.cnblogs.com/myEIT/ ]
两个造形的组合
将上述的Thread框架造形,与Android的其它框架造形,组合在一起,就形成一支可用的应用程序了。如下图:

图1-22 Thread造形与Activity造形的美丽组合
接下来,还可以调整一下结构,将两个应用子类合并起来。这是把run()函数写进Activity的子类别里。于是,可促成Thread造形与Activity造形的新组合,如下图所示:

图1-23 Activity造形与Thread造形的新组合
由于在这个程序只会诞生myActivity对象,却可能诞生多个Thread对象,可能出现多条线程同时并行(Concurrently)执行run()函数的情形。此时必须特别留意线程冲突问题。也就是多条线程共享变量或对象,导致互相干扰计算中的变量值,因而产生错误的计算结果。例如,依据上图的设计结构,撰写程序码,可能无意中这会产生冲突了,如下范例:
// myActivity.java (Ex01_04)
package com.misoo.pk002;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class myActivity extends Activity implements OnClickListener, Runnable {
private Button ibtn;
private int sum;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
ibtn = new Button(this); ibtn.setOnClickListener(this);
ibtn.setText("Exit"); ibtn.setBackgroundResource(R.drawable.gray);
LinearLayout.LayoutParams param1 =
new LinearLayout.LayoutParams(150, 55);
param1.topMargin = 10;
param1.leftMargin = 10;
layout.addView(ibtn, param1);
setContentView(layout);
//-----------------------------------------------
Thread th1 = new Thread(this); th1.start();
Thread th2 = new Thread(this); th2.start();
try { Thread.sleep(1000);
} catch (InterruptedException e) { e.printStackTrace(); }
setTitle(String.valueOf(sum));
}
public void onClick(View v) { finish(); }
//------------------------------------------
@Override public void run() {
sum = 0;
for(int i=0; i<10000; i++ )
sum += 1;
}
}
第一个线程还没做完run()函数的计算,其后的第二个线程就进来run()函数,并行共享了sum变量值,因而输出错误的结果:11373。
此时,可以使用synchronized机制来错开两个线程,就正确了。例如将上数程序码修改如下:
// …………
int sum;
Thread th1 = new Thread(this);
th1.start();
Thread th2 = new Thread(this);
th2.start();
Thread.sleep(1000);
setTitle(String.valueOf(sum));
// ………….
@Override public void run() {
this.exec();
}
public synchronized void exec(){
sum = 0;
for(int i=0; i<10000; i++ )
sum += 1;
}
// end
第二个线程会等待第一个线程离开exec()函数之后才能进入exec(),就不会产生共享sum变量值的现象了。由于变量就存于对象内部,如果不共享对象,就可避免共享内部变量的问题。
于是,我们可以改变组合,将上述图1-23的Thread造形,与Activity造形组合起来,就可以避免共享对象的问题;如下图所示:

图1-24 避免了多线程共享对象问题
依据此图,将上述Ex01_04的程序码修改如下:
//…………………
int sum;
myThread th1 = new myThread();
th1.start();
myThread th2 = new myThread();
th2.start();
Thread.sleep(1000);
setTitle(String.valueOf(th1.sum));
//………………….
class myThread extends Thread{
public int sum;
@Override
public void run() {
sum = 0;
for(int i=0; i<10000; i++ )
sum += 1;
}
}
}
// end
两个线程各使用自己的对象,也就是各自使用自己的sum变量值,就没有线程冲突问题了。
[Go Back]