步步为营_Android开发课[10]_Thread学习

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

时间: 2024-12-06 12:54:30

步步为营_Android开发课[10]_Thread学习的相关文章

步步为营_Android开发课[7]_AsyncTask学习

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:AsyncTask学习 -在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验.但是在子线程中无法去操作主线程(UI线程),在子线程中操作UI线程会出现错误.因此androi

步步为营_Android开发课[6]_ContentProvider学习

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:ContentProvider学习 ContentProvider是什么 ContentProvider(内容提供者)是Android中的四大组件之一.主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过Con

步步为营_Android开发课[4]_Intent学习

Focus on technology, enjoy life!-- 杨焕州 QQ:804212028 原文链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:Intent学习 -Intent(意图)主要是解决Android应用的各项组件之间的通讯问题.Intent消息传递是一种组件间运行时绑定的机制. Intent和Bundle机制 Intent和Bundle实现从一个Activity带参数转换到另一个Activit

步步为营_Android开发课[12]_Json学习

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:json学习 -JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. JSON采用完全独立于语言的文本格式,JSON是理想的数据交换语言.易于人阅读和编写,同时也易于机器解析和生成(网络传输速度). json的数据格式: 1.对

步步为营_Android开发课[5]_Service学习

Focus on technology, enjoy life!-- 杨焕州 QQ:804212028 原文链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:Service服务相关内容 -Android开发中Service服务是非常重要滴,也是有一定难度滴,不怕,我们一起一步一步来看: 一. Service简介 Service是android系统中的四大组件之一(Activity.Service.BroadcastR

步步为营_Android开发课[3]_Activity学习

Focus on technology, enjoy life!-- 杨焕州 QQ:804212028 原文链接:http://blog.csdn.net/y18334702058/article/details/44624305 本文可能存在参考或借助部分外界资源,如有任何侵权行为,请与我联系! 主题:Activity学习 -activity是用户和应用程序交互的窗口,在其上可以布置按钮,文本框等各种控件,简单来说就是Android的UI部分,在手机或平板电脑的屏幕上你看到的界面就是它喽! A

步步为营_Android开发课[11]_AIDL服务学习

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:AIDL服务 -AIDL(Android Interface Definition Language)即Android接口定义语言.Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信.我们知道4个Android应用程序组件中的3

步步为营_Android开发课[19]_用户界面之ListView(列表视图)

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:用户界面之ListView(列表视图) -ListView和TextView,Button等控件一样,一样的定义方式和显示方式,所以不再重复学了.但是Android开发中ListView经常适配一些适配器来显示,所以我们要学重点是是ListView的各种适配. List

步步为营_Android开发课[23]_用户界面之ProgressBar(进度条)

Focus on technology, enjoy life!-- QQ:804212028 浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305 主题:用户界面之ProgressBar(进度条) - 自定义ProgressBar进度条(实例): activity_main.xml: <?xml version="1.0" encoding="utf-8"?> <Linea