步步為營_Android開發課[10]_Thread學習

來源:互聯網
上載者:User

標籤:thread   android   開發   

Focus on technology, enjoy life!—— QQ:804212028
瀏覽連結:http://blog.csdn.net/y18334702058/article/details/44624305

  • 主題:Thread學習
    -當一個程式第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如:使用者的按鍵事件,使用者接觸螢幕的事件以及螢幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。

線程與進程的關係:

線程是進程中的實體,一個進程可以擁有多個線程,一個線程必須有一個父進程。

建立線程的兩種方式:

1.擴充java.lang.Thread類
擴充java.lang.Thread類,也就是把run()方法寫到線程裡面:

import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.widget.TextView;public class MainActivity extends Activity {    private TextView textView;          @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        textView = (TextView)findViewById(R.id.textView);        new Thread(new Runnable()          {              @Override              public void run()              {                  Message message=new Message();                  message.what=1;                  handler.sendMessage(message);              }          }).start();              }    Handler handler = new Handler(){        public void handleMessage(Message msg){            switch(msg.what){            case 1:                textView.setText("嘟嘟");                break;            }            super.handleMessage(msg);        }    };}

2.實現Runnable介面
讓類實現Runnable介面,讓run方法獨立出來

import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.TextView;public class MainActivity extends Activity implements Runnable {    private TextView textView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);       textView = (TextView)findViewById(R.id.textView);       Thread thread = new Thread();       thread.start();    }    Handler mHandler = new Handler(){        public void handleMessage(Message msg){            switch(msg.what){            case 1:                textView.setText("嘟嘟");                break;            }            super.handleMessage(msg);        }    };    @Override    public void run() {        // TODO Auto-generated method stub        Message msg = new Message();        msg.what = 1;        mHandler.sendMessage(msg);    }}

經典Thread賣票執行個體:(能讓我們更加理解線程的使用)

多個視窗一起賣火車票問題。假設有3個視窗同時售票,共有10張火車票代售。啟動三個線程賣共同的10張票。

1.我們開三個線程來賣票:

public class CommonTestActivity extends Activity{    private Button mybutton;    private TextView mytext;    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        mybutton = (Button) findViewById(R.id.button);        mytext = (TextView) findViewById(R.id.text);        mybutton.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                MyThread myThread1 = new MyThread();                 MyThread myThread2= new MyThread();                 MyThread myThread3 = new MyThread();                 myThread1.start();                 myThread2.start();                 myThread3.start();             }        });    }    class MyThread extends Thread {        private int tickets = 10;        public void run() {            for (int i = 0; i < 200; i++) {                if (tickets > 0) {                    System.out.println(Thread.currentThread().getName() + "==>"                            + tickets--);                }            }        }    }}

運行結果:

11-17 22:45:01.234: I/System.out(672): Thread-10==>10
11-17 22:45:01.234: I/System.out(672): Thread-10==>9
11-17 22:45:01.234: I/System.out(672): Thread-10==>8
11-17 22:45:01.234: I/System.out(672): Thread-10==>7
11-17 22:45:01.234: I/System.out(672): Thread-10==>6
11-17 22:45:01.234: I/System.out(672): Thread-10==>5
11-17 22:45:01.234: I/System.out(672): Thread-10==>4
11-17 22:45:01.234: I/System.out(672): Thread-10==>3
11-17 22:45:01.244: I/System.out(672): Thread-10==>2
11-17 22:45:01.244: I/System.out(672): Thread-10==>1
11-17 22:45:01.244: I/System.out(672): Thread-11==>10
11-17 22:45:01.244: I/System.out(672): Thread-11==>9
11-17 22:45:01.244: I/System.out(672): Thread-11==>8
11-17 22:45:01.244: I/System.out(672): Thread-11==>7
11-17 22:45:01.244: I/System.out(672): Thread-11==>6
11-17 22:45:01.254: I/System.out(672): Thread-11==>5
11-17 22:45:01.254: I/System.out(672): Thread-11==>4
11-17 22:45:01.254: I/System.out(672): Thread-11==>3
11-17 22:45:01.254: I/System.out(672): Thread-11==>2
11-17 22:45:01.254: I/System.out(672): Thread-11==>1
11-17 22:45:01.264: I/System.out(672): Thread-12==>10
11-17 22:45:01.264: I/System.out(672): Thread-12==>9
11-17 22:45:01.264: I/System.out(672): Thread-12==>8
11-17 22:45:01.264: I/System.out(672): Thread-12==>7
11-17 22:45:01.264: I/System.out(672): Thread-12==>6
11-17 22:45:01.274: I/System.out(672): Thread-12==>5
11-17 22:45:01.274: I/System.out(672): Thread-12==>4
11-17 22:45:01.274: I/System.out(672): Thread-12==>3
11-17 22:45:01.274: I/System.out(672): Thread-12==>2
11-17 22:45:01.274: I/System.out(672): Thread-12==>1

分析:
運行結果與預期不一致,分析可以看出3個線程各種賣各自的10張票,而不是共同的10張票。

2.只修改onClick裡面的代碼,並分析運行結果

public void onClick(View v) {     //執行個體化線程對象     MyThread myThread = new MyThread();     new Thread(myThread, "視窗1").start();     new Thread(myThread, "視窗2").start();     new Thread(myThread, "視窗3").start(); }

運行結果:

11-17 22:49:17.314: I/System.out(708): 視窗3==>10
11-17 22:49:17.314: I/System.out(708): 視窗3==>9
11-17 22:49:17.314: I/System.out(708): 視窗3==>8
11-17 22:49:17.314: I/System.out(708): 視窗3==>7
11-17 22:49:17.314: I/System.out(708): 視窗3==>6
11-17 22:49:17.324: I/System.out(708): 視窗3==>5
11-17 22:49:17.324: I/System.out(708): 視窗3==>4
11-17 22:49:17.324: I/System.out(708): 視窗3==>3
11-17 22:49:17.324: I/System.out(708): 視窗3==>2
11-17 22:49:17.324: I/System.out(708): 視窗3==>1

分析:
此處3個視窗本來是已經在賣共同的10張票了,只不過由於沒有進行線程同步,會隨機選定一個線程視窗來執行賣票直到賣完,致使其他視窗沒機會賣。

3.下面繼續修改代碼,驗證我剛得猜測。

public void onClick(View v) {     //執行個體化線程對象     MyThread myThread = new MyThread();     new Thread(myThread, "視窗1").start();     new Thread(myThread, "視窗2").start();     new Thread(myThread, "視窗3").start(); }class MyThread extends Thread{     private int tickets = 10;     public void run() {         for(int i = 0; i< 200; i++){                 sell();         }     }     public synchronized  void sell(){             if(tickets > 0)             {                 System.out.println(Thread.currentThread().getName() + "==>" + tickets--);             }     } }

運行結果:

05-11 08:53:31.986: INFO/System.out(7116): 視窗1==>10 05-11
08:53:32.006: INFO/System.out(7116): 視窗1==>9 05-11 08:53:32.016:
INFO/System.out(7116): 視窗1==>8 05-11 08:53:32.066:
INFO/System.out(7116): 視窗1==>7 05-11 08:53:32.086:
INFO/System.out(7116): 視窗1==>6 05-11 08:53:32.106:
INFO/System.out(7116): 視窗1==>5 05-11 08:53:32.106:
INFO/System.out(7116): 視窗1==>4 05-11 08:53:32.126:
INFO/System.out(7116): 視窗1==>3 05-11 08:53:32.146:
INFO/System.out(7116): 視窗1==>2 05-11 08:53:32.146:
INFO/System.out(7116): 視窗1==>1

分析:
一個對象只有一個鎖。所以,如果一個線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第這個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
上述代碼沒有Thread.sleep(10),換句話說線程一一直處於運行狀態,沒有釋放鎖,沒有給其他線程啟動並執行機會。

4.根據上述分析,修改代碼如下:

public void onClick(View v) {         //執行個體化線程對象         MyThread myThread = new MyThread();         new Thread(myThread, "視窗1").start();         new Thread(myThread, "視窗2").start();         new Thread(myThread, "視窗3").start();     }     class MyThread extends Thread{         private int tickets = 10;         public void run() {             for(int i = 0; i< 200; i++){                 try{                     sell();                     Thread.sleep(10);                 }catch (InterruptedException e) {                     System.out.println("我被打斷了" + Thread.currentThread().getName());                     e.printStackTrace();                 }            }         }         public synchronized  void sell(){                 if(tickets > 0)                 {                     System.out.println(Thread.currentThread().getName() + "==>" + tickets--);                 }         }     }

運行結果:

05-11 09:17:07.496: INFO/System.out(7898): 視窗1==>10
05-11 09:17:07.528: INFO/System.out(7898): 視窗1==>9
05-11 09:17:07.546: INFO/System.out(7898): 視窗1==>8
05-11 09:17:07.577: INFO/System.out(7898): 視窗1==>7
05-11 09:17:07.626: INFO/System.out(7898): 視窗3==>6
05-11 09:17:07.626: INFO/System.out(7898): 視窗2==>5
05-11 09:17:07.636: INFO/System.out(7898): 視窗1==>4
05-11 09:17:07.646: INFO/System.out(7898): 視窗2==>3
05-11 09:17:07.646: INFO/System.out(7898): 視窗1==>2
05-11 09:17:07.656: INFO/System.out(7898): 視窗3==>1

分析:
此次得出的正是我們想要的結果,現在知道火車站是怎麼賣票的啦。

//有的同學可能還不太理解上面程式中synchronized的用法,那我們繼續往下看

synchronized 主要用法

1.方法聲明時使用,放在範圍操作符(public等)之後,傳回型別聲明(void等)之前。即一次只能有一個線程進入該方法,其他線程要想在此時調用該方法,只能排隊等候,當前線程(就是在synchronized方法內部的線程)執行完該方法後,別的線程才能進入。
例如:

public synchronized void synMethod() {//方法體}

2.對某一代碼塊使用,synchronized後跟括弧,括弧裡是變數,這樣,一次只有一個線程進入該代碼塊。例如:

public int synMethod(int a1){synchronized(a1) {//一次只能有一個線程進入

Focus on technology, enjoy life!—— QQ:804212028
瀏覽連結:http://blog.csdn.net/y18334702058/article/details/44624305

步步為營_Android開發課[10]_Thread學習

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.