高并发(3)---线程的状态和常用方法

1、线程的运行原理

我们都知道虚拟机是由:堆、栈、方法区等组成,那么其中的栈内存是给谁使用的呢?

1)、每个线程启动后,虚拟机就会为其分配一块栈内存

2)、每个栈由多个栈帧(Frame)组成,对应的就是每次方法调用时所占用的内存

3)、每个线程只能有一个活动的栈帧,对应着当前正在执行的那个方法

线程上下文切换

因为如下的一些原因导致CPU不再执行当前的线程,转而执行另一个线程的代码

1)、线程的cpu时间片用完了

2)、垃圾回收,有更高优先级的线程需要运行

3)、线程自己调用了sleep、yield、wait、join、park、synchronized、lock等方法。

当线程上下文发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,java中对应的概念就是程序计数器(program counter register),它的作用就是记住下一条jvm指令的执行地址,是线程私有的。

2、线程的状态

从java API层面来看,根据Thread.State枚举,线程分为6种状态

1)、新建状态(new)

创建了一个线程,但是还没有调用start()方法

如:通过Runnable接口创建一个线程类,new一个实例出来,线程就进入了初始状态。

2)、运行状态(Runnable)

java中将就绪(ready)和运行中(running)两种状态统称之为运行状态

那么什么是就绪状态?

就绪说明你有资格运行,调度程序没有挑选到你,你就永远处于就绪状态;

调用线程的start()方法,此时线程就进入了就绪状态;

当前线程时间片用完了,调用当前线程的yield()方法,当前线程就进入了就绪状态

当前线程sleep()方法结束,其它线程join()结束,等待用户输入完毕,某个线程就拿到了对象锁,这些线程也将进入就绪状态

锁池里的线程拿到对象锁后,也进入就绪状态。

运行中状态(running):

线程调度程序从可运行池中选择一个线程作为当前线程所处的状态,这也是线程进入运行状态的唯一的一种方式。

3)、阻塞状态(blocked)

表示线程阻塞于锁;阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块时(获取锁)的状态

4)、等待状态(waiting)

进入该状态的线程需要等待其它线程作出一些特定的动作(如通知或中断)

进入这种状态的线程不会被分配cpu执行时间片,它们要等待被显示的唤醒,否则会处于无限等待的状态。

5)、超时等待状态(timed_waiting)

该状态不同于waiting,它可以在指定的时间后自行返回,处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其它线程显示的唤醒,在达到一定时间后他们会自动唤醒。

6)、终止状态(terminated)

表示该线程已经执行完毕。

3、线程的状态转换

1)、新建状态(new):新创建了一个线程对象

2)、就绪状态(runnable):线程对象创建后,其它线程调用了该对象的start()方法。

该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3)、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码

4)、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃了CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

阻塞的情况分为三种:

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

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

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

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

4、线程调度

4.1、线程的优先级

1)、java的线程有优先级,优先级高的线程获得较多的运行机会。

2)、java线程的优先级用整数表示,取值范围为1~10,Thread类有如下三个静态常量

         

static int MAX_PRIORITY:线程可以具有的最高优先级,取值为10
static int MIN_PRIORITY:线程可以具有的最低优先级,取值为1
static int NORM_PRIORITY:分配给线程的默认优先级,取值为5

3)、Thread类的setPriority()和getPriority()方法分别用了设置和获取线程的优先级

4)、每个线程都有默认的优先级,主线程的默认优先级为Thread.NORM_PRIORITY

5)、线程的优先级有继承关系,比如:A线程中创建了B线程,那么B将和A具有相同的优先级

6)、JVM提供了10个线程优先级,党羽常见的操作系统都不能很好的映射,如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类的三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。

4.2、线程睡眠:sleep()

Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

1)、sleep()方法属于Thread类,主要作用是让当前线程停止执行,将cpu让给其它线程执行。如果有锁,不会释放锁,等睡眠期满之后,恢复为可运行状态,等到切换为运行状态时继续运行。

2)、线程睡眠到期后自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间,因此,sleep()方法不能保证该线程睡眠到其后就开始执行。

3)、

Thread.state;   //静态方法
sleep(long millis);     //1秒=1000ms
sleep(long millis,int nanos);  //millis是毫秒,nanos是纳秒

4)、为什么要让线程睡眠?因为线程执行太快,或者需要强制进入下一轮。

睡眠位置:为了让其它线程有机会执行,可以将Thread.sleep()的调用放在线程run()之内,这样才能保证该线程在执行过程中会睡眠

package com.wzy.day08;

public class TestSleep {
    public static void main(String[] args) {
        MyThread myThread=new MyThread("wzy");
        myThread.start();
        for(int i=0;i<10;i++){
            System.out.println("i am Main Thread");
        }
    }
}
class MyThread extends Thread{
    MyThread(String name){
        super(name);
    }
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            System.out.println("i'm "+getName());

        }
    }
}

线程睡眠到期自动苏醒,并返回到可运行状态,而不是运行状态

4.3、线程等待:wait()

Object类中的wait()方法,导致当前线程等待,直到其它线程调用此对象的notify()方法或者notifyAll()唤醒方法。这两个唤醒方法也是Object类中的方法,行为等价于调用wait(0)一样

4.4、线程让步:yield()

Thread.yield()方法,用于暂停当前正在执行的线程对象,将执行机会让给相同或者更高优先级的线程

4.5、线程加入:join()

join()方法,等待其它线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

4.6、线程唤醒:notify()、notifyAll()

Object的notify()方法,唤醒在此对象监视器上等待的单个线程。

如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在实现做出决定时发生。

线程通过调用其中一个wait()方法

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值