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.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