多线程详解(二)
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、每一条路径上独立的进行压栈弹栈,每一条线程上都要自己的栈区,所以互相不影响
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具备执行资格和执行权,此时其他三个具备执行资格但正在等待执行权,这种状态就是临时阻塞状态
所以,临时阻塞状态———具备执行资格但是不具备执行权
在一个时刻,只有一个线程拥有执行权,而其他运行的线程都是临时阻塞的。
如果原来的类已经继承了其他类,使用第一种方式继承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());
}
}
从上面的示例我们可以看出,多增加一层继承关系,其实是开发者强制加上去的,而且实现过程也很繁琐,所以我们应该抛弃此方法,重新思考……..
为什么第三步中,要将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());
}
}
运行结果: