在做nachos操作系统实验的时候,多次看到runnable的出现,但是不懂是什么意思,所以查阅资料,整理了一下有关Runnable的知识。
在java中,有两种方式实现多线程:继承thread,或实现Runnable接口。
thread和runnable的对比:
package test1;
public class MyThread extends Thread{
private String name;
public MyThread(String name)
{
super();
this.name=name;
}
public void run()
{
for(int i=0;i<5;i++)
{
System.out.println("线程:"+this.name+"的第"+i+"次运行");
}
}
}
package test1;
import test1.MyThread1;
public class ThreadTest1 {
public static void main(String[] args) {
MyThread m1=new MyThread("线程1");
MyThread m2=new MyThread("线程2");
new Thread(m1).run();
new Thread(m2).run();
}
}
result:
线程:线程1的第0次运行
线程:线程1的第1次运行
线程:线程1的第2次运行
线程:线程1的第3次运行
线程:线程1的第4次运行
线程:线程2的第0次运行
线程:线程2的第1次运行
线程:线程2的第2次运行
线程:线程2的第3次运行
线程:线程2的第4次运行
从上面可以看出,用run执行时,结果很规律,线程1先运行完,线程2才运行。
用start启动线程时:
package test1;
import test1.MyThread1;
public class ThreadTest1 {
public static void main(String[] args) {
MyThread m1=new MyThread("线程1");
MyThread m2=new MyThread("线程2");
new Thread(m1).start();
new Thread(m2).start();
}
}
线程:线程1的第0次运行
线程:线程2的第0次运行
线程:线程1的第1次运行
线程:线程2的第1次运行
线程:线程1的第2次运行
线程:线程2的第2次运行
线程:线程1的第3次运行
线程:线程2的第3次运行
线程:线程1的第4次运行
线程:线程2的第4次运行
线程1和线程2交替执行。
为什么结果不一样?
在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface)。意思是start才可以调用底层函数,执行多线程动作。
package test1;
public class MyThread1 implements Runnable{
private String name;
public MyThread1(String name)
{
this.name=name;
}
public void run()
{
for(int i=0;i<5;i++)
{
System.out.println("线程:"+this.name+"的第"+i+"次运行");
}
}
}
运行结果:
线程:线程1的第0次运行
线程:线程1的第1次运行
线程:线程1的第2次运行
线程:线程1的第3次运行
线程:线程1的第4次运行
线程:线程2的第0次运行
线程:线程2的第1次运行
线程:线程2的第2次运行
线程:线程2的第3次运行
线程:线程2的第4次运行
但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程。(start()可以协调系统的资源)。
在程序实现时,多用runnable,因为一个类可以实现多个接口,而且runnable可以实现多线程资源共享。
如果继承Thread,初始化三个实例,则这三个实例各自运行不会做到资源共享。
若实现接口Runnable,可以用一个thread实例初始化得到。