java线程(一):线程创建与线程状态

来源:互联网 发布:复制淘宝口令没反应 编辑:程序博客网 时间:2024/05/21 07:37

      关于线程,线程是java中非常重要的一部分。很多程序的设计离开不了对线程的设计。多任务本质上就是实现多线程。多线程是实现多任务的一种。说到线程必须要提到进程,进程指的是在内存中运行的应用程序,每个进程都有自己的运行内存空间,一个进程可以启动多个线程。java.lang.Thread类实例中每个线程都有一个调用栈。

      java程序总是从main()方法开始执行,main方法存放在一个线程内,成为主线程。一旦创建新线程就会产生新的调用栈。

 关于用户线程和守候线程

      User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。我们知道JVM里面有垃圾回收器的存在,其实垃圾回收就可以认为是守护线程的功能之一。

 线程创建的两种方式

1)通过实现Runnable接口实现 。还是直接来看例子:

class compute implements Runnable {    int i = 0;    public void run() {        for (int i = 0; i < 10; i++) {            System.out.println(i);        }    }}class compute1 implements Runnable {    public void run() {        for (int i = 0; i < 10; i++) {            System.out.println("这个数字是:" + i);        }    }}

      以上就创建一个线程类,只不过该线程的功能比较简单:仅仅是输出一些提示信息。线程在执行其实就是运行run()方法,因此不同的线程最鲜明的不同之处在于run()方法不同。

public class threadtest {    public static void main(String[] args) {        compute c = new compute();        compute1 c1 = new compute1();        Thread t = new Thread(c);        Thread t1 = new Thread(c1);        t.start();        t1.start();    }}

      启动这两个线程的语句是t.start(); t1.start();让其交替执行。结果输出可能是:

0这个数字是:0123456789这个数字是:1这个数字是:2这个数字是:3这个数字是:4这个数字是:5这个数字是:6这个数字是:7这个数字是:8这个数字是:9

      那就很奇怪了,为啥不是先输出数字0~9 再输出“数字0~9”呢?要想实现跟自己预期一样的结果需要进行线程之间的同步。这个后面会详细说明,先还是从简单入手吧,来看看线程的状态。

这里写图片描述

      从图可以得知,线程一个有五个状态。分别为新状态、就绪状态(也称之为可运行状态)、运行状态、阻塞/等待/睡眠状态、死亡状态。

新建状态:线程对象已经创建、还没有在其上调用start()方法。我们理解为在调用strat()之前线程状态。新建以后会分配内存,不可运行。

就绪状态: 调用start()。

运行状态:线程调度代码从可运行线程池中选择一个线程作为当前线程所处状态。

等待/阻塞/休眠状态:线程是活的,但是当前无条件运行

死亡状态:run()方法完成时认为死去,线程对象也许是活的,一旦死去不可复生,继续调用start(),会抛出java.lang.IlleagelThreadStateException异常。

      分析上面的输出问题需要明白线程的五种状态之间的关系。注意运行状态:调用start()后启动线程,处于此状态下的线程位于java虚拟机可运行状态池中,等待获取cpu资源。JVM线程调度器调度获得CPU资源后,线程占用CPU运行,执行run方法。如果只有一个CPU那么任何时刻都只有一个线程处于该状态。多CPU同一时刻可以几个线程占用不同的cpu,可同时运行。

从以上线程的生命周期中可以发现,由于cpu资源不能被一个线程一直占有,故输出不是我们想象的那样。解决办法就是加同步锁(后续章节会有详细说明)。

2) 对Thread类的继承创建线程

给出另外一种创建线程的实例:

class compute2 extends Thread  {    int i=0;    public void run()    {        for(int i=0;i<10;i++)        {            System.out.println(i);        }    }}class compute3 extends Thread {    public void run()    {        for(int i=0;i<10;i++)        {            System.out.println("这个数字是:"+i);        }    }}

      创建的两个线程类与之前的两个线程类功能不变,重写run()。注意这种条件下与另外一种的不同之处:

public class threadtTest{    public static void main(String[] args)    {        compute2 t=new compute2();        compute3 t1=new compute3();        t.start();        t1.start();    }}

      直接实例化线程对象 t、t1。还是用start()启动线程进行可运行/就绪状态。输出结果可能是一下一种:

0这个数字是:0这个数字是:1这个数字是:2这个数字是:3这个数字是:4这个数字是:5这个数字是:6这个数字是:7这个数字是:8这个数字是:9123456789
0 0
原创粉丝点击