Java、安卓的线程理解系列一(一篇就够了)

基础知识篇

一、线程的状态

  (这方面知识极力推荐去看孙老师的《Java面向对象编程》) 

    首先我们要理解线程的状态。

    1.新建状态:用new语句创建的线程处于新建状态,与其他new出来的对象一样,仅仅是在堆区分配了内存

    2.就绪状态:当一个线程对象被创建后,调用其start()方法,该线程就进入就绪状态,处于这个状态的线程位于可运行池中,等待CPU的使用权

    3.运行状态:一般计算机只有一个CPU,那么任何时刻只有一个线程占用CPU,处于这个状态。当然,有些计算机有多个CPU,那么同一时刻就有几个线程占用不同的CPU。记住只有处于就绪状态的线程才有机会转到运行状态。

    4.阻塞状态:线程因为某些原因放弃CPU,暂时停止运行。主要有三种:

- 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。 

- 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。 

- 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 

    5.死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

二、线程的状态变化有关的方法

 线程的状态发生改变总是与下面几个方法有关。

    1、sleep()线程睡眠方法:当一个线程在运行状态执行了sleep()方法,它就会放弃CPU,转到阻塞状态。当它结束了阻塞状态,它就进入就绪状态,在可运行池中等待获得CPU(获得CPU的时机往往是另一个线程运行结束)。

    2、yield()线程让步方法:当一个线程在运行状态执行了yield()方法,如果此时具有相同优先级或者更高优先级的其他线程处于就绪状态,yield()方法将把当前运行状态的线程转为就绪状态,放到可运行池中并使另外一个线程处于运行状态。如果没有具有相同优先级的其他线程处于就绪状态,yield()方法上面也不做。

    3、join()线程等待其他线程结束方法:当一个线程在运行状态调用了另一个线程的join()方法,当前线程将转到阻塞状态,直至另一个线程运行结束,它才回复到就绪状态,最后恢复运行状态。

   这里注意:sleep()和yield()都是使线程放弃CPU,让其他线程获得运行的机会。但是两者是有区别的:sleep()方法是不考虑其他线程优先级给其他线程运行机会的,yield()方法考虑优先级。sleep()方法使当前线程转到堵塞状态,yield()方法使当前线程转到就绪状态。sleep()方法据说比yield()方法具有更好的移植性。

   4、wait()线程通信的方法:当一个线程执行到wait()方法时,它就进入一个和该对象相关的等待池中,同时释放了该对象锁。使得其他线程可以访问。

    5、notify()、notifyAll()线程通信的方法:notify(),执行该方法的线程随机唤醒在对象相关的等待池中等待的一个线程,把它转到对象的锁池中,如果对象相关的等待池中没有线程,则notify()什么也不做。notifyAll(),执行该方法的线程唤醒在对象相关的等待池中等待的所有线程,把它们转到对象的锁池中。

  这里注意:wait()、notify()、notifyAll()必须放在synchronized修饰的代码块中,否则会抛出异常。

   例子:在waitAndNotifyAll()主线程函数中,会启动一个WaitThread线程,在该线程中将会调用sleep函数睡眠3秒钟。线程启动后,主线程调用sLockObject对象的wait函数,使主线程进入sLockObject对象的等待池,此时主线程不会继续执行,等WaitThread在run函数中睡眠3秒后会调用sLockObject的notifyAll函数,唤醒sLockObject对象等待池中的主线程,主线程继续执行。

                                    

三、线程的调度

    上面说到计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令。所谓多线程的并发运行,其实是各个线程轮流获得CPU的使用权,分别执行各自的任务。线程调度是指按照特定的机制为多个线程分配CPU的使用权,有两种调度模型:分时调度模型和抢占式调度模型。

    分时调度模型是指让所有线程轮流获得CPU的使用权,平且平均分配每个线程占用CPU的时间片。

    Java虚拟机采用的抢占式调度模型,它是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中线程的优先级同相同,那么就随机地选择一个线程运行,使其占有CPU,并且一直处于运行状态直到该线程自己运行结束。当然,线程也会不得不放弃CPU,其原因有多种:Java虚拟机让当前线程暂时放弃CPU使其他线程获得运行机会、当前线程因为某些原因进入阻塞状态。

    下面这个例子就能说明两个同优先级的线程1、2同时启动,Java虚拟机随机选择一个线程运行,使其占有CPU,运行结束后再执行另一个线程。

线程:

  public class Machine implements Runnable{
        private int a = 1;

        @Override
        public void run() {
            for(int i= 0; i < 5; i++){
                a+=i;
                a-=i;
                Log.i("Test:"+currentThread(),"a="+a);//按当前线程打印
            }
        }
    }

主函数:

        Machine machine1 = new Machine();
        Thread t1 = new Thread(machine1);
        Thread t2 = new Thread(machine1);
        t1.start();//线程1启动
        t2.start();//线程2启动

一种可能的打印结果:(由图可见先执行完[Thread-3,5,main],再执行[Thread-2,5,main])

02-25 13:33:57.223 3399-3415/com.pikamouse.thread I/Test:Thread[Thread-3,5,main]: a=1
02-25 13:33:57.223 3399-3415/com.pikamouse.thread I/Test:Thread[Thread-3,5,main]: a=1
02-25 13:33:57.223 3399-3415/com.pikamouse.thread I/Test:Thread[Thread-3,5,main]: a=1
02-25 13:33:57.223 3399-3415/com.pikamouse.thread I/Test:Thread[Thread-3,5,main]: a=1
02-25 13:33:57.223 3399-3415/com.pikamouse.thread I/Test:Thread[Thread-3,5,main]: a=1
02-25 13:33:57.225 3399-3414/com.pikamouse.thread I/Test:Thread[Thread-2,5,main]: a=1
02-25 13:33:57.225 3399-3414/com.pikamouse.thread I/Test:Thread[Thread-2,5,main]: a=1
02-25 13:33:57.225 3399-3414/com.pikamouse.thread I/Test:Thread[Thread-2,5,main]: a=1
02-25 13:33:57.225 3399-3414/com.pikamouse.thread I/Test:Thread[Thread-2,5,main]: a=1
02-25 13:33:57.225 3399-3414/com.pikamouse.thread I/Test:Thread[Thread-2,5,main]: a=1

    既然上面说到了运行池中的线程有优先级,我们来谈谈怎样设置线程的优先级。Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。Thread类有3个静态常量:

    MAX_PRIORITY:取值为10,表示优先级最高

    NORM_PRIORITY:取值为5,表示默认优先级(主线程的默认优先级)

    MIN_PRIORITY:取值为1,表示优先级最低

注意:不同的系统线程的优先级分类是不同的,所以一般为了程序能移植到各中系统中使用,建议只用上面提到的三种优先级

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值