在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
1.继续Thread类
T.java
/**
* User: liuwentao
* Date: 2011-5-5 18:36:31
* <p/>
* 说明:
*/
public class T extends Thread {
public T() {
}
public T(String threadName) {
super(threadName);
}
public void run() {
String threadName = super.getName();
System.out.println(threadName + " 线程运行开始!");
for (int i = 0; i < 5; i++) {
double sleepTime = Math.random() * 10;
System.out.println(i + " " + threadName + ",sleepTime=" + sleepTime);
try {
sleep((int)sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(threadName + " 线程运行结束!");
}
}
TestT.java
/**
* User: liuwentao
* Date: 2011-5-5 18:37:01
* <p/>
* 说明:
*/
public class TestT {
/**
* main方法其实也是一个线程
* @param rags
*/
public static void main(String[] rags) {
Thread currentThread = Thread.currentThread();
String currentThreadName = currentThread.getName();
System.out.println("******" + currentThreadName + " 线程运行开始!");
T t1 = new T("Thread-A");
//如果我们没有指定名字的话,系统自动提供名字。如:Thread-0
T t2 = new T();
t1.start();
t2.start();
System.out.println("******" + currentThreadName + " 线程运行结束!");
}
}
执行结果
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
注意:
1:启动线程一定是 start()方法,而不是run()方法,如果写成run()方法启动
t1.run();
t2.run();
执行结果:
就全变成 顺序执行的了。这是不对的。
为什么我们不能直接调用run()方法呢?因为线程的运行需要本地操作系统的支持。 如果查看start的源代码的时候,会发现:
public synchronized void start() {
if (threadStatus != 0 || this != me)
throw new IllegalThreadStateException();
group.add(this);
//这个方法有native关键字
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
/**
* native关键字表示调用本地操作系统的函数。
* 因为多线程的实现需要本地操作系统的支持。
*/
private native void start0();
2:start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
如写成这样:
t1.start();
t2.start();
t1.start();
执行结果:
可以看到程序抛出了异常,
引用
******main 线程运行结束!
这句话不会出现
2.实现Runnable接口
R.java
/**
* User: liuwentao
* Date: 2011-5-5 18:36:31
* <p/>
* 说明:
*/
public class R implements Runnable {
private String name;
public R() {
}
public R(String threadName) {
this.name = threadName;
}
public void run() {
System.out.println(name + " 线程运行开始!");
for (int i = 0; i < 5; i++) {
int j = 0;
while (j < 1000000) {
j++;
}
System.out.println(i + " " + name);
}
System.out.println(name + " 线程运行结束!");
}
}
TestR.java
/**
* User: liuwentao
* Date: 2011-5-5 18:37:01
* <p/>
* 说明:
*/
public class TestR {
public static void main(String[] rags) {
System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
R r1 = new R("A");
R r2 = new R("B");
Thread thread1 = new Thread(r1);
thread1.start();
Thread thread2 = new Thread(r2);
thread2.start();
System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
}
}
执行结果:
其实Thread也是实现Runnable接口的:
Thread和Runnable的区别:
1:实现Runnable接口的多线程程序要通过 类似下面方式启动
R r1 = new R("A");
Thread thread1 = new Thread(r1);
thread1.start();
而继承Thread类的多线程程序,则可以直接调用start()方法启动:
T t1 = new T("Thread-A");
t1.start();
2:Thread类中有一些方法,是Runnable接口中没有的,比如:
引用
sleep
yield
stop
等
2:如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
/**
* 继承Thread类,不能资源共享
* */
class hello extends Thread {
private int count = 5;
public void run() {
for (int i = 0; i < 7; i++) {
if (count > 0) {
System.out.println("count= " + count--);
}
}
}
public static void main(String[] args) {
hello h1 = new hello();
hello h2 = new hello();
hello h3 = new hello();
h1.start();
h2.start();
h3.start();
}
}
执行结果
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。
换为Runnable接口:
/**
* 实现Runnable接口,能资源共享
* */
class hello implements Runnable {
private int count = 5;
public void run() {
for (int i = 0; i < 7; i++) {
if (count > 0) {
System.out.println("count= " + count--);
}
}
}
public static void main(String[] args) {
hello he=new hello();
new Thread(he).start();
}
}
执行结果
count= 5
count= 4
count= 3
count= 2
count= 1
总结一下:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
所以建议大家劲量实现接口。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。