多线程详解(二)
来源:互联网 发布:互联网 中文域名 编辑:程序博客网 时间:2024/06/14 07:11
多线程详解(二)
在正式介绍线程创建的第二种方法之前,我们接着多线程详解(一),讲一下:对线程的内存图、线程的状态,为下面的学习打下基础,小伙伴们不要急哟!!
一、多线程运行的内存图(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());}}
运行结果:
关于多线程创建的第二种方法的详细介绍,请阅读多线程详解(三)
- 多线程详解(二)
- Java 多线程详解(二)
- Java多线程详解(二)
- 高级应用JAVA多线程详解(二)
- Java-多线程机制详解(二)
- Java中多线程详解(二)
- Java 多线程实例详解(二)
- 多线程(二)volatile关键字详解
- C#多线程详解(二)
- Java----多线程详解(二)
- Java多线程详解(二)
- 孙鑫MFC深入详解 第十五章 多线程(二)
- Android-多线程断点下载详解及源码下载(二)
- JAVA进阶学习-多线程基础详解(二)-同步
- 【Java多线程】之二:synchronized详解
- java 多线程详解二 买票示例
- java 多线程详解二 买票示例
- 多线程同步(二)
- 旅游计划(树形dp)
- [数据结构]Graph之入度与出度计算
- 使用shiro进行权限管理
- Linux下安装Redis及安装php扩展
- 轻松搞定Intelli Idea Maven配置
- 多线程详解(二)
- 开发小注意
- Volley
- 【实务附案例】有关电子合同的法律问题全解
- laravel中pipeline中间件调用
- Java反射(二)----- 动态加载类
- 设计模式之抽象工厂(C++实现)
- linux 中断机制的处理过程
- Java(六) final用法实例讲解