面试真相:Thread与Runnable的区别,别再被面试官的谣言误导了

0 下载量 101 浏览量 更新于2024-09-01 收藏 227KB PDF 举报
"面试中的Java多线程知识误区——Thread与Runnable的区别" 在Java编程中,多线程是不可或缺的一部分,而面试时经常会有面试官询问Thread类和Runnable接口之间的差异。然而,有些面试官提出的问题可能基于网络上流传的误解。这里我们将深入探讨这两个关键概念,并揭示一些常见的误区。 首先,Thread类是Java中用于创建和管理线程的内置类,它直接继承自Object类,因此无法多重继承。而Runnable接口是一个可以被实现的接口,允许类同时实现其他接口,提供了更大的灵活性。这是两者最直观的区别。 学妹在面试中提到的两点区别,即Thread的单继承限制和Runnable在资源共享上的优势,实际上并不完全准确。虽然Thread类的单继承确实限制了其扩展性,但这并不意味着Thread在资源共享上无能为力。事实上,无论是通过继承Thread还是实现Runnable,都可以实现线程间的资源共享。 让我们通过具体的代码示例来澄清这一点。在Java中,无论是使用Thread的子类还是实现Runnable接口,共享数据通常都是通过实例变量实现的。以下是一个使用Thread子类的例子: ```java public class MyThreadWithExtends extends Thread { private int tickets = 10; @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (this) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "--卖出票:" + tickets--); } } } } public static void main(String[] args) { MyThreadWithExtends thread1 = new MyThreadWithExtends(); MyThreadWithExtends thread2 = new MyThreadWithExtends(); MyThreadWithExtends thread3 = new MyThreadWithExtends(); thread1.start(); thread2.start(); thread3.start(); } } ``` 在这个例子中,尽管MyThreadWithExtends继承自Thread,但它依然可以通过共享tickets变量实现多线程间的同步。通过使用`synchronized`关键字,确保了在任何时候只有一个线程能够访问并修改tickets。 同样的,如果我们选择实现Runnable接口,代码会有所不同,但资源共享的机制是相同的: ```java public class MyRunnable implements Runnable { private int tickets = 10; @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (this) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "--卖出票:" + tickets--); } } } } public static void main(String[] args) { MyRunnable task = new MyRunnable(); Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); Thread thread3 = new Thread(task); thread1.start(); thread2.start(); thread3.start(); } } ``` 在这段代码中,我们创建了多个Thread对象,它们共享同一个Runnable实例,从而实现资源共享。 因此,Thread和Runnable在资源共享的能力上并没有本质区别。关键在于如何正确地管理和同步共享数据,以避免并发问题。面试时,更应该关注候选人在多线程同步、锁机制、并发工具类(如Semaphore、CyclicBarrier)等高级主题上的理解和应用能力,而不是仅仅停留在Thread和Runnable的区别上。