多线程详解(二)

版权声明:本文为博主原创文章,请勿转载。 https://blog.csdn.net/Neil_Wesley/article/details/51694116

多线程详解(二)

在正式介绍线程创建的第二种方法之前,我们接着多线程详解(一),讲一下:对线程的内存图、线程的状态,为下面的学习打下基础,小伙伴们不要急哟!!

一、多线程运行的内存图(ps.博主没有找到合适的画图工具,欢迎大神们贡献啊)

class person extends Thread
{   
    int i;
    private String name;
    person(String name)
    {
//给线程命名,使用super
        super(name);
        this.name=name;
    }
    public void run()
    {
        show();
    }

    public void show()
    {
        for(i=0;i<=10;i++)
        {
            System.out.println(name+"x="+i+"...name="+Thread.currentThread().getName());
        }
    }
}
public class demo1{
public static void main(String[] args){
    person p1=new person("zhangsan");
    person p2=new person("lisi");
    p1.start();
    p2.start();
    System.out.println("出来吧,name="+Thread.currentThread().getName());
}
}

每开启一条线程就多一条运行路径,所以以上述代码为例——共有三条路径

    (1)main线程路径
    (2)run线程路径
    (3)另一条run线程路径

1、每一条路径上独立的进行压栈弹栈,每一条线程上都要自己的栈区,所以互相不影响

2、当一条路劲上的代码运行完,该线程自动结束

3、当main线程提前运行结束后,其他两条线程依旧运行。所以可以看出每条线程之间是完全独立的,当一条线程有异常时,其他的线程继续运行不受影响。

4、为多线程安全分析埋下伏笔(这里不详细讲多线程安全了,以后会更行的哦)

二、线程的状态(重点)

1、运行(使用start方法):具备执行资格和执行权

2、消亡(任务运行完了,自动消亡OR使用stop方法强制消亡):既不具备执行资格也不具备运行资格

3、冻结:

《1》使用sleep(time)方法———时间到了,自动恢复————既不拥有执行权也不拥有执行资格(释放执行权的同时释放执行资格)

《2》使用wait()方法————使用notify()方法唤醒————既不拥有执行权也不拥有执行资格(释放执行权的同时释放执行资格))

解释:如果一个线程处于运行状态,那么CPU就具备执行资格和拥有CPU的执行权,那么什么是执行权?什么又是执行资格呢??

《1》CPU执行资格:CPU可以处理,在CPU的队列中排队等待处理

《2》CPU执行权:正在被CPU处理

下面我们通过举一个例子,解释一下什么是临时阻塞

假设A、B、C、D四个线程都处于执行状态,当A运行的时候,A具备执行资格和执行权,此时其他三个具备执行资格但正在等待执行权,这种状态就是临时阻塞状态

所以,临时阻塞状态———具备执行资格但是不具备执行权

在一个时刻,只有一个线程拥有执行权,而其他运行的线程都是临时阻塞的。

辨析:临时阻塞状态和冻结状态的区别
    (1)执行资格和执行权的不同
    (2)冻结是由程序员控制的而临时阻塞是cpu运行控制的
    (3)临时阻塞的时间往往是极短的,但是冻结的时间是自定义的,相比较而言是长的。
    (4)临时阻塞是运行时的一种状态,所以冻结唤醒后,必须经过运行才能有时间阻塞。

三、创建线程的第二种方式

1、继承Thread类创建方法的局限性

如果原来的类已经继承了其他类,使用第一种方式继承Thread,就存在了多继承,在java中是不允许的

例如:

class person extends fu
{   int i;
    private String name;
    person(String name)
    {   
        super(name);
        this.name=name;
    }
    public void run()
    {
        show();
    }

    public void show()
    {
        for(i=0;i<=10;i++)
        {
            System.out.println(name+"x="+i+"...name="+Thread.currentThread().getName());
        }
    }
}
public class demo1{
public static void main(String[] args){
    person p1=new person("zhangsan");
    person p2=new person("lisi");
    p1.start();
    p2.start();
    System.out.println("出来吧,name="+Thread.currentThread().getName());
}
}

但是在这种情况下,如果你依旧要使用继承Thread的方法创建线程也是可以的,就是利用再增加一层继承的方法来实现。示例如下:

class fu extends Thread
{
     int i;
    private String name;
    person(String name)
    {
        super(name);
        this.name=name;
    }
    public void run()
    {
        show();
    }

    public void show()
    {
        for(i=0;i<=10;i++)
        {
            System.out.println(name+"x="+i+"...name="+Thread.currentThread().getName());
        }
    }
}
class person extends fu
{      
}
public class demo1{
public static void main(String[] args){
    person p1=new person("zhangsan");
    person p2=new person("lisi");
    p1.start();
    p2.start();
    System.out.println("出来吧,name="+Thread.currentThread().getName());
}
}

从上面的示例我们可以看出,多增加一层继承关系,其实是开发者强制加上去的,而且实现过程也很繁琐,所以我们应该抛弃此方法,重新思考……..

2、使用接口的方法创建线程

我们现在的目的是让person类创建一个线程,但是person类不可以再继承。由于需要扩展person类功能,所有我们很自然的想到使用————接口

创建步骤:

    《1》定义类实现Runnable接口
    《2》覆盖接口中的run方法,将线程的任封装到run方法中
    《3》通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数进行传递。
    《4》调用线程对象的start方法开启线程

为什么第三步中,要将Runnable接口的子类对象作为Thread类的构造函数进行传递呢?

因为,线程的任务都是封装在Runnable接口子类对象的run方法中。所以要在线程对象创建时就明确要运行的任务。

示例代码如下:

//实现Runable接口,
class person implements Runnable
{   int i;
    private String name;
    person(String name)
    {
        this.name=name;
    }
//  覆盖run方法
    public void run()
    {
        show();
    }

    public void show()
    {
        for(i=0;i<=10;i++)
        {
            System.out.println(name+"x="+i+"...name="+Thread.currentThread().getName());
        }
    }
}
public class demo1{
public static void main(String[] args){
//这个不是线程对象
//  person p1=new person("zhangsan");
//  person p2=new person("lisi");
//这个是线程对象
    person p=new person("zhangsan");

    Thread t1=new Thread(p);
    Thread t2=new Thread(p);
    t1.start();
    t2.start();
    System.out.println("出来吧,name="+Thread.currentThread().getName());
}
}

运行结果:

这里写图片描述

关于多线程创建的第二种方法的详细介绍,请阅读多线程详解(三)

猜你喜欢

转载自blog.csdn.net/Neil_Wesley/article/details/51694116