深入Android架构(从线程到AIDL)_13 线程安全的化解之例

目录

7、 线程安全的化解之例

复习:Android单线程环境

非单线程环境的线程安全议题

       范例-1

范例-2​编辑

同步(Synchronization)化解线程安全的问题


7、 线程安全的化解之例

复习:Android单线程环境
  • View是一个单线程的类;其意味着:此类的撰写着心中意图只让有一个线程来执行这个类的代码(如函数调用)。

       

   

  • 由于View类开发者心怀<单线程>,则View类的Client开发者就不宜让多线程去执行View的代码。

 

// ac01.java
// ……..
public class ac01 extends Activity implements OnClickListener {
    private Button btn;
    public void onCreate(Bundle icicle) {
        // ……..
        btn = new Button(this);
        btn.setText(“Exit");
        // ……..
    }

    public void f1() {
        // ……..
        btn.setText(“OK");
        // ……..
    }
}
  • 同样地, View的子类开发者也不宜让多线程去执行View(基类)的代码。
    /* ---- ac01.java ---- */
    // ……..
    public class ac01 extends Activity {
        @Override 
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            okButton ok_btn = new okButton(this);
            LinearLayout.LayoutParams param =
                new LinearLayout.LayoutParams(ok_btn.get_width(),
            ok_btn.get_height());
            // ……..
        }
    }
    
    /* ---- okButton ---- */
    // ……….
    public class okButton extends Button{
        public okButton(Context ctx){
            super(ctx);
            super.setText("OK");
            super.setBackgroundResource(R.drawable.ok_blue);
        }
    
        public void f1() {
            super.setText("Quit");
        }
    
        public int get_width(){ return 90; }
        public int get_height(){ return 50; }
    }
非单线程环境的线程安全议题
  • 如果共享对象或变量是不可避免的话,就得试图错开线程的执行时刻了。
  • 由于共享对象或变量,若两个线程会争相更改对象的属性值或变量值时,则可能会互相干扰对方的计算过程和结果。 例如:
       范例-1
class Task implements Runnable {
    private int count;
    public void init(){ count = 0; }
    
    public void f1() {
        for(int i=0; i<3; i++) {
            count++;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) { e.printStackTrace(); }

            System.out.println(Thread.currentThread().getName() +"'s count: " + count);
        }
    }

    public void run() {
        this.init();
        this.f1();
    }
}

public class JMain {
    public static void main(String[] args) {
        Task ta = new Task();
        Thread t1 = new Thread( ta, "A");
        Thread t2 = new Thread( ta, "B");
        t1.start();
        t2.start();
        System.out.println("Waiting...");
    }
}
范例-2
  • 由于在这个程序只会诞生myActivity对象,却可能诞生多个Thread对象,可能出现多条线程同时并行(Concurrently)执行run()函数的情形。此时必须特别留意线程冲突问题。也就是多条线程共享变量或对象,导致互相干扰计算中的变量值,因而产生错误的计算结果。
  • 例如,依据上图的设计结构,撰写程序码,可能无意中这会产生冲突了。
  • 如下范例:
// myActivity.java
//……….
public class myActivity extends Activity implements OnClickListener, Runnable {
    private Button ibtn;
    private int sum;

    @Override
    protected void onCreate(Bundle icicle) {
        //………
        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。

       

同步(Synchronization)化解线程安全的问题
  • 此时,可以使用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变量值的现象了。由于变量就存于对象内部,如果不共享对象,就可避免共享内部变量的问题。
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

思忖小下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值