关于Thread类和Runnable接口的具体内容可参考我上一篇博客:Java 基础学习之多线程一 (Thread、Runnable)声明: 本博客的是实例代码,不规范,正式写代码时把 main() 放到一个单独的类中会更规范一点。

1. Thread类和Runnable接口在定义上和使用上的的区别与联系

  1. 定义上: 先观察 Thread 类的定义public class Thread extends Object implements Runnable ,可以发现 Thread 类也是 Runnable 接口的子类,但在 Thread 类中并没有完全实现 Runnable 接口中的 run() 方法。而且 Thread 类中的 run() 方法调用的是 Runnable 接口中的 run() 方法,也就是说此类方法是由 Runnable 子类完成的。所以,如果要继承 Thread 类实现多线程,则必须覆写 run() 方法。
  2. 使用上 也是有区别的:如果一个类继承 Thread 类,则不适合于多个线程共享资源,而实现了 Runnable 接口,就可以很方便的实现资源共享。

2. Thread类和Runnable接口在使用上的比较 — 能否资源共享

2.1 继承Thread类 不能实现资源共享

实例1代码:
package self.learn.thread;

public class ThreadDemo2 extends Thread {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadDemo2 thread1 = new ThreadDemo2();           // 定义线程对象
		ThreadDemo2 thread2 = new ThreadDemo2();
		ThreadDemo2 thread3 = new ThreadDemo2();
		thread1.start();
		thread2.start();
		thread3.start();
	}
	private int tickets = 5;                                // 一共 5 张票      
	public void run() {                                     // 覆写 run() 方法
		for(int i = 0; i < 100; i++) {                      // 超出票数的循环
			if(tickets > 0) {                               // 判断是否有剩余的票
				System.out.println("卖票:tickets="+tickets--);
			}

		}
	}	
}
运行结果截图:

java thread runnable java thread runnable区别_覆写


   上面的程序通过 Thread 类实现多线程,程序中启动了 3 个线程,但是 3 个线程分别卖了 5 张票,并没有达到资源共享的目的。

2.2 实现 Runnable接口实现资源共享

实例2代码:
package self.learn.thread;

public class ThreadDemo implements Runnable{                 // 实现 Runnable 接口

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadDemo thread1 = new ThreadDemo();
		new Thread(thread1).start();                        // 启动 3 个线程
		new Thread(thread1).start(); 
		new Thread(thread1).start(); 
	}
	private int tickets = 5;                                // 一共 5 张票      
	public void run() {                                     // 覆写 run() 方法
		for(int i = 0; i < 100; i++) {                      // 超出票数的循环
			if(tickets > 0) {
				System.out.println("卖票:tickets="+tickets--);
			}

		}
	}

}
运行结果截图:

java thread runnable java thread runnable区别_多线程_02


   程序中虽然启动了 3 个线程,但是 3 个线程一共卖了 5 张票,即 tickets 属性被所有线程对象共享。

3. 实现 Runnable 接口相对于继承 Thread 类来说,有如下优势:

  1. 适合多个相同程序代码块的线程去处理同一资源的情况。
  2. 可以避免由于 Java 单继承特性所带来的局限性。
  3. 增强了代码的健壮性,代码能够被多个线程共享,代码与数据是独立的。
       所以,在开发中建议读者使用 Runnable 接口实现多线程。

4. 常见面试题:请解释多线程的两种实现方式及其区别?分别编写程序以验证两种实现方式。

(1)多线程的两种实现方式都需要一个线程的主类,而这个类可以实现 Runnable 接口或者继承 Thread 类,不管使用何种方式都必须在子类中 覆写 run() 方法,此方法为线程的主方法。
(2)Thread 类是 Runnable 接口的子类,而使用 Runnable 可以避免单继承局限性,以及更方便地实现数据共享。 (3)程序实现结构:

Runnable 接口

Thread 类

class MyThread implements Runnable{ public void run() { // 线程操作方法 } }

class MyThread extends Thread { public void run() { // 线程操作方法 } }

MyThread mt = new MyThread(); new Thread(mt).start();

Mythread mt = new Mythread(); mt.start();