21. 实现多线程的两种方法:Thread与Runable。
Thread是Class,要求单一继承,不能再继承其他类,有一定的局限性;Runable是接口Inteface,接口可以实现多个,方便拓展。
在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
1.start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
2.run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
下面通过几个代码实例了解执行过程:
/**
*
* @author:Mars
* @version Revision 1.0.0
* @see:
* @创建日期:2018年1月30日
* @功能说明:
*/
public class ThreadDemo extends Thread {
int j = 0;
@Override
public void run() {
while (j<100) {
System.err.println("ThreadDemo...."+j);
j++;
}
}
}
/**
*
* @author:Mars
* @version Revision 1.0.0
* @see:
* @创建日期:2018年1月30日
* @功能说明:
*/
public class RunnableDemo implements Runnable {
int i = 0;
@Override
public void run() {
while (i<100) {
System.err.println("RunnableDemo..."+i);
++i;
}
}
public static void main(String[] args) {
//写法一:
RunnableDemo runnableDemo = new RunnableDemo();
// new Thread(runnableDemo).start();
ThreadDemo threadDemo = new ThreadDemo();
// threadDemo.start();//run();
//写法二:
threadDemo.run();
runnableDemo.run();
}
}
下图主要说明 继承Thread,其实也是实现了Runnable接口,因为父类实现了该接口。
分别创建了2个线程实例,然后启动他们,具体看清各种启动方式的区别,两个均start启动,体现了线程此刻就绪状态,一旦有资源,便开始执行,实质就是cpu的轮询切换对应到线程的轮询切换执行。
方法二执行方式:第一个run,第二start,结果并未交叉执行,因为一旦run启动,线程直接开始执行,不再等待,直到完毕。可以理解为他就是正常的程序,非多线程实现方式。
切换方式后,依旧交叉执行,因为第一个首先会就绪好,然后执行到第二个,一有资源释放,第一个立刻执行。
最后,都run的时候,结果也一样,线性执行。