概述
很显然,这些对象仅仅是作为线程而创建的,并不具有其它任何行为。然而,你的类也许
已经继承了其它的类,在这种情况下,就不可能同时继承Thread(Java并不支持多重继
承)。这时,你可以使用“实现Runnable接口”的方法作为替代。要实现Runnable接口,
只需实现run( )方法,Thread也是从Runnable接口实现而来的。
以下例子演示了这种方法的要点:
//: c13:RunnableThread.java
// SimpleThread using the Runnable interface.
publicclass RunnableThreadimplements Runnable {
privateint countDown = 5;
public String toString() {
return"#" + Thread.currentThread().getName() +
": " + countDown;
}
publicvoid run() {
while(true) {
System.out.println(this);
if(--countDown == 0)return;
}
}
publicstaticvoid main(String[] args) {
for(int i = 1; i <= 5; i++)
new Thread(new RunnableThread(),"" +
i).start();
// Output is like SimpleThread.java
}
}///:~
Runnable 类型的类只需一个 run( )方法,但是如果你想要对这个 Thread 对象做点别
的事情(比如在 toString( )里调用 getName( )),那么你就必须通过调用
Thread.currentThread( )方法明确得到对此线程的引用。这里采用的 Thread 构造器
接受一个 Runnable 对象和一个线程名称作为其参数。
当某个对象具有Runnable接口,即表明它有run( )方法,但也就仅此而已,不像从Thread
继承的那些类,它本身并不带有任何和线程有关的特性。所以要从Runnable对象产生一个
线程,你必须像例子中那样建立一个单独的Thread对象,并把Runnable对象传给专门的
Thread构造器。然后你可以对这个线程对象调用start( ),去执行一些通常的初始化动
作,然后调用run( )。
Runnable接口的方便之处在于所有事物都属于同一个类;也就是说,Runnable允许把基
类和其它接口混在一起。如果你要访问某些资源,只需直接去做,而不用通过别的对象。
不过,内部类也能同样方便地访问外部类的所有部分,所以,成员访问并不是使用Runnalbe
接口形成混和类,而不是“一个Thread子类类型的内部类”的强制因素。
当你使用了Runnable,你通常的意思就是,要用run( )方法中所实现的这段代码创建一
个进程(process),而不是创建一个对象表示该进程。这一点是有争议的,取决于你认
为把线程作为一个对象来表示,或是作为完全不同的一个实体,即进程来表示,这两种方
式哪一种更具实际意义1。如果你觉得应该是一个进程,你就不必拘泥于面向对象的原则,
即“所有事物都是对象”。这也意味着,如果仅仅是想开启一个进程以驱动程序的某个部分,
就没有理由把整个类写成是Runnable类型的。因此,使用内部类把和线程有关的代码隐藏
在类的内部,似乎更合理,如下所示:
//: c13:ThreadVariations.java
// Creating threads with inner classes.
import com.bruceeckel.simpletest.*;
// Using a named inner class:
class InnerThread1 {
privateint countDown = 5;
private Inner inner;
privateclass Innerextends Thread {
Inner(String name) {
super(name);
start();
}
publicvoid run() {
while(true) {
System.out.println(this);
if(--countDown == 0)return;
try {
sleep(10);
} catch (InterruptedException e) {
thrownew RuntimeException(e);
}
}
}
public String toString() {
return getName() +": " + countDown;
}
}
public InnerThread1(String name) {
inner = newInner(name);
}
}
// Using an anonymous inner class:
classInnerThread2 {
private int countDown = 5;
private Thread t;
public InnerThread2(String name) {
t = newThread(name) {
public void run() {
while(true){
System.out.println(this);
if(--countDown == 0) return;
try{
sleep(10);
} catch(InterruptedException e) {
throw newRuntimeException(e);
}
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
// Using a named Runnable implementation:
classInnerRunnable1 {
private int countDown = 5;
private Inner inner;
private class Inner implements Runnable {
Thread t;
Inner(String name) {
t= newThread(this,name);
t.start();
}
public void run() {
while(true){
System.out.println(this);
if(--countDown == 0) return;
try{
Thread.sleep(10);
} catch(InterruptedException e) {
throw newRuntimeException(e);
}
}
}
public String toString() {
return t.getName() + ":" + countDown;
}
}
public InnerRunnable1(String name) {
inner = newInner(name);
}
}
// Using an anonymous Runnableimplementation:
classInnerRunnable2 {
private int countDown = 5;
private Thread t;
public InnerRunnable2(String name) {
t = newThread(newRunnable() {
public void run() {
while(true){
System.out.println(this);
if(--countDown == 0) return;
try{
Thread.sleep(10);
} catch(InterruptedException e) {
throw newRuntimeException(e);
}
}
}
public String toString() {
return Thread.currentThread().getName() +
": " + countDown;
}
},name);
t.start();
}
}
// A separate method to run some code as athread:
classThreadMethod {
private int countDown = 5;
private Thread t;
private String name;
public ThreadMethod(String name) { this.name =
name; }
public void runThread() {
if(t == null){
t= newThread(name) {
public void run() {
while(true){
System.out.println(this);
if(--countDown == 0) return;
try{
sleep(10);
} catch(InterruptedException e) {
throw newRuntimeException(e);
}
}
}
public String toString() {
return getName() + ": " + countDown;
}
};
t.start();
}
}
}
public class ThreadVariations {
private static Test monitor = new Test();
public static void main(String[] args) {
newInnerThread1("InnerThread1");
newInnerThread2("InnerThread2");
newInnerRunnable1("InnerRunnable1");
newInnerRunnable2("InnerRunnable2");
newThreadMethod("ThreadMethod").runThread();
monitor.expect(new String[] {
"InnerThread1: 5",
"InnerThread2: 5",
"InnerThread2: 4",
"InnerRunnable1: 5",
"InnerThread1: 4",
"InnerRunnable2: 5",
"ThreadMethod: 5",
"InnerRunnable1: 4",
"InnerThread2: 3",
"InnerRunnable2: 4",
"ThreadMethod: 4",
"InnerThread1: 3",
"InnerRunnable1: 3",
"ThreadMethod: 3",
"InnerThread1: 2",
"InnerThread2: 2",
"InnerRunnable2: 3",
"InnerThread2: 1",
"InnerRunnable2: 2",
"InnerRunnable1: 2",
"ThreadMethod: 2",
"InnerThread1: 1",
"InnerRunnable1: 1",
"InnerRunnable2: 1",
"ThreadMethod: 1"
},Test.IGNORE_ORDER + Test.WAIT);
}
} ///:~
InnerThread1 创建了一个命名的内部类,它继承自 Thread,并且在构造器中创建了一
个此内部类的实例。如果你需要在别的方法中访问此内部类(比如新的方法),这么做就
显得很合理。不过,绝大多数时候创建一个线程的原因仅仅是为了使用 Thread的功能,
所以建立一个命名的内部类往往没有必要。InnerThread2 演示了另一种选择:在构造器
内部建立了一个匿名内部类,它也继承自 Thread,同时它被向上转型为对 Thread的引
用 t。如果该类的别的方法需要访问 t,它们可以通过 Thread的接口访问,并且不需要知
道这个对象的确切类型。
例子中的第三、四个类和前两个大致相同,但是它们实现了 Runnable接口而不是从
Thread 继承。这只不过表明了在实现 Runnable接口的情况下,并没有带来更多好处,
而且实际上代码要稍微复杂一些(读起来也是)。所以,除非被迫使用 Runnable,否则
我更倾向于使用Thread。
ThreadMethod 类演示了如何在方法内部创建一个线程。当你调用该方法准备运行这个线
程时,在线程启动后该方法返回。当线程只是做一些辅助工作,而不是作为类的基本功能
的时候,这种方案就比在类的构造器中启动一个线程显得更合理。
最后
以上就是勤劳白云为你收集整理的编码的变体的全部内容,希望文章能够帮你解决编码的变体所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复