Android -- Thread

创建线程的方法:

官网的说法:

[plain] view plain copy
  1. There are basically two main ways of having a Thread execute application code.   
  2. One is providing a new class that extends Thread and overriding its run() method.   
  3. The other is providing a new Thread instance with a Runnable object during its creation. In both cases, the start() method must be called to actually execute the new Thread.  

扩展Thread的示例代码:

[java] view plain copy
  1. public class CommonTestActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.           
  8.         new Thread(){  
  9.             public void run(){  
  10.                 System.out.println("Thread is running.");  
  11.             }  
  12.         }.start();  
  13.     }  
  14. }  

使用Runnable的示例代码:

[java] view plain copy
  1. public class CommonTestActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.           
  8.         new Thread(r).start();  
  9.     }  
  10.       
  11.     Runnable r = new Runnable() {  
  12.         @Override  
  13.         public void run() {           
  14.             System.out.println("Runnable running ");  
  15.         }  
  16.     };  
  17.       
  18. }  

经典实例:

多个窗口一起卖火车票问题。假设有3个窗口同时售票,共有10张火车票代售。启动三个线程卖共同的10张票。

1. 使用下面的代码试图实现功能

[java] view plain copy
  1. public class CommonTestActivity extends Activity{  
  2.       
  3.     private Button mybutton;  
  4.     private TextView mytext;  
  5.   
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.         mybutton = (Button) findViewById(R.id.button);  
  10.         mytext = (TextView) findViewById(R.id.text);  
  11.           
  12.         mybutton.setOnClickListener(new OnClickListener() {  
  13.   
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 // TODO Auto-generated method stub  
  17.                 MyThread myThread1 = new MyThread();   
  18.                 MyThread myThread2= new MyThread();   
  19.                 MyThread myThread3 = new MyThread();   
  20.                 myThread1.start();   
  21.                 myThread2.start();   
  22.                 myThread3.start();   
  23.             }  
  24.         });  
  25.          
  26.     }  
  27.   
  28.     class MyThread extends Thread {  
  29.         private int tickets = 10;  
  30.   
  31.         public void run() {  
  32.             for (int i = 0; i < 200; i++) {  
  33.                 if (tickets > 0) {  
  34.                     System.out.println(Thread.currentThread().getName() + "==>"  
  35.                             + tickets--);  
  36.                 }  
  37.             }  
  38.         }  
  39.     }  
  40.   
  41. }  
输出如下

[plain] view plain copy
  1. 11-17 22:45:01.234: I/System.out(672): Thread-10==>10  
  2. 11-17 22:45:01.234: I/System.out(672): Thread-10==>9  
  3. 11-17 22:45:01.234: I/System.out(672): Thread-10==>8  
  4. 11-17 22:45:01.234: I/System.out(672): Thread-10==>7  
  5. 11-17 22:45:01.234: I/System.out(672): Thread-10==>6  
  6. 11-17 22:45:01.234: I/System.out(672): Thread-10==>5  
  7. 11-17 22:45:01.234: I/System.out(672): Thread-10==>4  
  8. 11-17 22:45:01.234: I/System.out(672): Thread-10==>3  
  9. 11-17 22:45:01.244: I/System.out(672): Thread-10==>2  
  10. 11-17 22:45:01.244: I/System.out(672): Thread-10==>1  
  11. 11-17 22:45:01.244: I/System.out(672): Thread-11==>10  
  12. 11-17 22:45:01.244: I/System.out(672): Thread-11==>9  
  13. 11-17 22:45:01.244: I/System.out(672): Thread-11==>8  
  14. 11-17 22:45:01.244: I/System.out(672): Thread-11==>7  
  15. 11-17 22:45:01.244: I/System.out(672): Thread-11==>6  
  16. 11-17 22:45:01.254: I/System.out(672): Thread-11==>5  
  17. 11-17 22:45:01.254: I/System.out(672): Thread-11==>4  
  18. 11-17 22:45:01.254: I/System.out(672): Thread-11==>3  
  19. 11-17 22:45:01.254: I/System.out(672): Thread-11==>2  
  20. 11-17 22:45:01.254: I/System.out(672): Thread-11==>1  
  21. 11-17 22:45:01.264: I/System.out(672): Thread-12==>10  
  22. 11-17 22:45:01.264: I/System.out(672): Thread-12==>9  
  23. 11-17 22:45:01.264: I/System.out(672): Thread-12==>8  
  24. 11-17 22:45:01.264: I/System.out(672): Thread-12==>7  
  25. 11-17 22:45:01.264: I/System.out(672): Thread-12==>6  
  26. 11-17 22:45:01.274: I/System.out(672): Thread-12==>5  
  27. 11-17 22:45:01.274: I/System.out(672): Thread-12==>4  
  28. 11-17 22:45:01.274: I/System.out(672): Thread-12==>3  
  29. 11-17 22:45:01.274: I/System.out(672): Thread-12==>2  
  30. 11-17 22:45:01.274: I/System.out(672): Thread-12==>1  

分析:

运行结果与预期不一致,分析可以看出3个线程各种卖各自的10张票,而不是共同的10张票。

在上面的代码中,只能保证:每个线程都将启动,每个线程都将运行直到完成。一系列线程以某种顺序启动并不意味着将按该顺序执行。对于任何一组启动的线程来说,调度程序不能保证其执行次序,持续时间也无法保证。


2. 只修改onClick里面的代码,并分析运行结果

[java] view plain copy
  1. public void onClick(View v) {   
  2.     //实例化线程对象   
  3.     MyThread myThread = new MyThread();   
  4.     new Thread(myThread, "窗口1").start();   
  5.     new Thread(myThread, "窗口2").start();   
  6.     new Thread(myThread, "窗口3").start();   
  7. }  

输出如下

[plain] view plain copy
  1. 11-17 22:49:17.314: I/System.out(708): 窗口1==>10  
  2. 11-17 22:49:17.314: I/System.out(708): 窗口1==>9  
  3. 11-17 22:49:17.314: I/System.out(708): 窗口1==>8  
  4. 11-17 22:49:17.314: I/System.out(708): 窗口1==>7  
  5. 11-17 22:49:17.314: I/System.out(708): 窗口1==>6  
  6. 11-17 22:49:17.324: I/System.out(708): 窗口1==>5  
  7. 11-17 22:49:17.324: I/System.out(708): 窗口1==>4  
  8. 11-17 22:49:17.324: I/System.out(708): 窗口1==>3  
  9. 11-17 22:49:17.324: I/System.out(708): 窗口1==>2  
  10. 11-17 22:49:17.324: I/System.out(708): 窗口1==>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

分析:

此次得出的正是我们想要的结果

你可能感兴趣的:(Android -- Thread)