线程创建方式,实现Runable接口与继承Thread类的比较

想要理解通过Runnable接口与继承Thread类两种创建线程方式的不同,首先要清楚任务与线程的区别。
你应该看到要执行的任务与驱动它的线程之间有一个差异,这个差异在Java类库中尤为明显,因为你对Thread类实际没有任何控制权(并且这种隔离在使用执行器是更加明显,因为执行器将替你处理线程的创建和管理)。你创建任务,并通过某种方式将一个任务附着到线程上,以使得这个线程可以驱动任务。
在Java中,Thread类自身不执行任何操作,它只是驱动赋予它的任务。线程不是任务,一旦某个类实现了Runnable接口,就意味着它要在run()方法中执行某项任务,只有需要驱动这种任务时,才把它附着在一个线程上。

因此很容易认识到他们的区别:

  • 实现Runnable接口后,必须要重写run()方法;继承Thread后,可以不重写run()方法,(根据接口和类的定义也很好理解)。
  • 实现Runnable接口的类,它run()中的任务需要通过Thread驱动;继承Thread类的子类,可通过start()方法直接驱动run()中的任务(Thread默认不执行任何操作并返回)。
public class RunExample implements Runnable{
	private static int countDown = 5;
	//必须重写run()方法
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(countDown>0) {
			System.out.println("#"+"("+(countDown--)+")");
		}
		System.out.println("Liftoff!");
	}
	//驱动run()方法中的任务时,需要附着在一个Thread对象上
	public static void main(String[] args) {
		Thread t = new Thread(new RunExample()) ;
				t.start();
	}
}
public class ThreadExample extends Thread{
	private static int countDown = 5;
	//可以不重写run()方法,那样的话可默认不执行任何任务并返回
	public void run() {
		while(countDown>0) {
			System.out.println("#"+"("+(countDown--)+")");
		}
		System.out.println("Liftoff!");
	}
	//驱动时直接运用start()方法
	public static void main(String[] args) {
		new ThreadExample().start();
	}
}

我们还可以用一种非常巧妙的方法,对run()方法实现“自我驱动”,即在实现了Runnable接口的类中内置一个Thread线程,把自身附着在Thread上,并在这个类的构造方法中用这个内置的Thread启动任务,这样的话只要这个类的对象已创建,就自行执行任务。

  1. private Thread t = new Thread(this);
  2. public SelfRunExample() { t.start(); }
  3. new SelfRunExample();
public class SelfRunExample implements Runnable{
	private static int countDown = 5;
	
	private Thread t = new Thread(this);
	public SelfRunExample() {
		t.start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(countDown>0) {
			System.out.println("#"+"("+(countDown--)+")");
		}
		System.out.println("Liftoff!");
	}
	public static void main(String[] args) {
		new SelfRunExample();
	}
}

这与从Thread继承并没有什么特别差异,但是创建对象时不用写.start()了,而且这样可以使它可以继承另一个不同的类,而从Thread继承不行。(因为Java不支持多继承)

这样也有缺点,因为在构造器中执行线程可能会变得很有问题,因为另一个任务可能会在构造器结束之前执行,这意味着该任务能够访问处于不稳定状态的对象。这也是优选Executor而不是显式地创建Thread对象的另一个原因。

有时通过使用内部类来将线程代码隐藏在类中将会很有用。

class InnerThread1 {
	private int countDown = 5;
	private Inner inner;
	private class Inner extends Thread{
		Inner(String name){
			super(name);
			start();
		}
		public void run() {
			try {
				while(true) {
					System.out.print(this);
					if(--countDown==0)
						return;
					sleep(10);
				}
			}catch(InterruptedException e) {
				System.out.print("interrupted");
			}
		}
		public String toString() {
			return getName()+": "+countDown;
		}
	}
	public InnerThread1(String name) {
		inner = new Inner(name);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值