继承Thread实现多线程
package dd20161117;
public class OtherThread extends Thread {
private int tickets = 20;
private boolean isGo = true;
public void run() {
while (isGo) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "出售票"
+ tickets--);
} else if (tickets == 0) {
isGo = false;
}
}
}
}
package dd20161117;
public class ThreadDemo {
public static void main(String[] args) {
OtherThread otherThread=new OtherThread();
otherThread.start();
otherThread.start();
otherThread.start();
otherThread.start();
}
}
结果:
Thread-0出售票20Exception in thread "main"
Thread-0出售票19
Thread-0出售票18
Thread-0出售票17
Thread-0出售票16
Thread-0出售票15
Thread-0出售票14
Thread-0出售票13
Thread-0出售票12
Thread-0出售票11
Thread-0出售票10
Thread-0出售票9
Thread-0出售票8
Thread-0出售票7
Thread-0出售票6
Thread-0出售票5
Thread-0出售票4
java.lang.IllegalThreadStateException
Thread-0出售票3
Thread-0出售票2
Thread-0出售票1
at java.lang.Thread.start(Unknown Source)
at dd20161117.ThreadDemo.main(ThreadDemo.java:7)
OtherThread类的实例化对象,之后调用了四次 start()方法,但在运行结果可以发现,程序运行时出现了异常,之后却只有一个线程在运行。这也就说明了一个类继承 Thread 类之后,这个类的对象无论调用多少次 start()方法,结果都只有一个线程在运行。
修改之后:
package dd20161117;
public class ThreadDemo {
public static void main(String[] args) {
OtherThread otherThread1=new OtherThread();
OtherThread otherThread2=new OtherThread();
OtherThread otherThread3=new OtherThread();
OtherThread otherThread4=new OtherThread();
otherThread1.start();
otherThread2.start();
otherThread3.start();
otherThread4.start();
}
}
输出结果:
Thread-2出售票20
Thread-3出售票20
Thread-1出售票20
Thread-0出售票20
Thread-1出售票19
Thread-3出售票19
Thread-2出售票19
....
Thread-0出售票3
Thread-2出售票1
Thread-0出售票2
Thread-0出售票1
从这部分输出结果中可以发现,这里启动了四个线程对象,但这四个线程对象,各自占有各自的资源,所以可以得出结论,用 Thread 类实际上无法达到资源共享的目的。
那么用runnbale如何呢?
2. 通过实现Runnable实现多线程
package dd20161117;
public class OtherRunnable implements Runnable {
private int tickets = 20;
private boolean isGo = true;
public void run() {
while (isGo) {
synchronized (this) {
if (tickets > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售票"
+ tickets--);
} else if (tickets == 0) {
isGo = false;
}
}
}
}
}
package dd20161117;
public class ThreadDemo {
public static void main(String[] args) {
OtherRunnable otherRunnable=new OtherRunnable();
// 启动了四个线程,并实现了资源共享的目的
new Thread(otherRunnable).start();
new Thread(otherRunnable).start();
new Thread(otherRunnable).start();
new Thread(otherRunnable).start();
}
}
输出结果:
Thread-0出售票20
Thread-3出售票19
Thread-3出售票18
Thread-3出售票17
Thread-2出售票16
Thread-2出售票15
Thread-1出售票14
Thread-1出售票13
Thread-2出售票12
Thread-2出售票11
Thread-2出售票10
Thread-2出售票9
Thread-3出售票8
Thread-0出售票7
Thread-3出售票6
Thread-3出售票5
Thread-3出售票4
Thread-2出售票3
Thread-2出售票2
Thread-1出售票1
从程序的
输出结果来看,尽管启动了四个线程对象,但是结果都是操纵了同一个资源,实现了资源共享的目的。结论,通过实现runnable实现的多线程实现了资源共享的目的
可见,实现 Runnable 接口相对于继承 Thread 类来说,有如下显著的优势:
( 1)、 适合多个相同程序代码的线程去处理同一资源的情况,把虚拟 CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。
( 2)、 可以避免由于 Java 的单继承特性带来的局限。开发中经常碰到这样一种情况,即:当要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承 Thread 类的方式,那么就只能采用实现 Runnable 接口的方式了。
( 3)、 增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程可以操作相同的数据,与它们的代码无关。当共享访问相同的对象时,即共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable 接口的类的实例。
事实上,几乎所有多线程应用都可用第二种方式,即实现 Runnable 接口。