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