標籤: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學習