Java-Thread Vs Runnable
在阅读Thread和Runnable之间的重大区别时,我遇到了一个不同之处:
当您扩展Thread类时,每个线程都会创建唯一对象并与之关联。 在哪里
实现Runnable时,它将同一对象共享给多个线程。 。
有代码给:
class ImplementsRunnable implements Runnable { private int counter = 0; public void run() { counter++; System.out.println("ImplementsRunnable : Counter : " + counter); } } class ExtendsThread extends Thread { private int counter = 0; public void run() { counter++; System.out.println("ExtendsThread : Counter : " + counter); } } public class ThreadVsRunnable { public static void main(String args[]) throws Exception { //Multiple threads share the same object. ImplementsRunnable rc = new ImplementsRunnable(); Thread t1 = new Thread(rc); t1.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread Thread t2 = new Thread(rc); t2.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread Thread t3 = new Thread(rc); t3.start(); //Creating new instance for every thread access. ExtendsThread tc1 = new ExtendsThread(); tc1.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread ExtendsThread tc2 = new ExtendsThread(); tc2.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread ExtendsThread tc3 = new ExtendsThread(); tc3.start(); } }
输出是这样的:
ImplementsRunnable : Counter : 1 ImplementsRunnable : Counter : 2 ImplementsRunnable : Counter : 3 ExtendsThread : Counter : 1 ExtendsThread : Counter : 1 ExtendsThread : Counter : 1
它certificate了上面给出的差异。 我在下面给出的代码中稍作修改:
class ImplementsRunnable implements Runnable { private int counter = 0; public void run() { counter++; System.out.println("ImplementsRunnable : Counter : " + counter); } } class ExtendsThread extends Thread { private int counter = 0; public void run() { counter++; System.out.println("ExtendsThread : Counter : " + counter); } } public class ThreadVsRunnable { public static void main(String args[]) throws Exception { //Multiple threads share the same object. ImplementsRunnable rc = new ImplementsRunnable(); Thread t1 = new Thread(rc); t1.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread Thread t2 = new Thread(rc); t2.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread Thread t3 = new Thread(rc); t3.start(); //Modification done here. Only one object is shered by multiple threads here also. ExtendsThread extendsThread = new ExtendsThread(); Thread thread11 = new Thread(extendsThread); thread11.start(); Thread.sleep(1000); Thread thread12 = new Thread(extendsThread); thread12.start(); Thread.sleep(1000); Thread thread13 = new Thread(extendsThread); thread13.start(); Thread.sleep(1000); } }
现在输出是:
ImplementsRunnable : Counter : 1 ImplementsRunnable : Counter : 2 ImplementsRunnable : Counter : 3 ExtendsThread : Counter : 1 ExtendsThread : Counter : 2 ExtendsThread : Counter : 3
我理解这样的事实,这里同一个对象(extendsThread)由三个线程共享。 但我在这里很困惑,它与实现Runnable有何不同。 在这里,即使* ExtendsThread *扩展了Thread,我们仍然可以将此类的对象共享给其他线程。 在我看来,上述差异没有任何意义。
谢谢。
这是javadoc所说的内容
有两种方法可以创建新的执行线程。 一种是将类声明为Thread的子类 。 该子类应该重写Thread类的run方法。 然后可以分配和启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:
创建线程的另一种方法是声明一个实现Runnable接口的类。 该类然后实现run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,然后启动。 此其他样式中的相同示例如下所示:
所以这两种方式
public class MyThread extends Thread { // overriden from Runnable, which Thread implements public void run() { ... } } ... MyThread thread = new MyThread(); thread.start();
要么
public class MyRunnable implements Runnable{ public void run() { ... } } ... Thread thread = new Thread(new MyRunnable()); thread.start();
您的counter
字段是实例字段。
在第一种情况下,这里创建的每个对象
ExtendsThread tc1 = new ExtendsThread(); tc1.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread ExtendsThread tc2 = new ExtendsThread(); tc2.start(); Thread.sleep(1000); // Waiting for 1 second before starting next thread ExtendsThread tc3 = new ExtendsThread(); tc3.start();
将拥有自己的副本(这就是实例变量的工作原理)。 因此,当您启动每个线程时,每个线程都会增加其自己的字段副本。
在第二种情况下, 您使用Thread
子类作为Thread
构造函数的Runnable
参数。
ExtendsThread extendsThread = new ExtendsThread(); Thread thread11 = new Thread(extendsThread); thread11.start(); Thread.sleep(1000); Thread thread12 = new Thread(extendsThread); thread12.start(); Thread.sleep(1000); Thread thread13 = new Thread(extendsThread); thread13.start(); Thread.sleep(1000);
它与您传递的ExtendsThread
对象相同,因此其counter
字段会被所有线程递增。 它几乎等同于您之前使用的ImplementsRunnable
。
要从评论中添加:
首先要理解的是Thread
类实现了Runnable
,因此您可以在任何可以使用Runnable
地方使用Thread
实例。 例如,
new Thread(new Thread()); // won't do anything, but just to demonstrate
使用时创建Thread
new Thread(someRunnable);
并启动它, 该线程调用给定的Runnable
实例的run()
方法 。 如果Runnable
实例恰好也是Thread
一个实例,那就这样吧。 这不会改变任何事情。
当你创建一个自定义线程时
new ExtendsThread();
并启动它,它自己调用run()
。
实现Runnable的主要区别在于您不“消耗”单个inheritance。 考虑这些类声明:
public class HelloRunnable implements Runnable extends AbstractHello public class HelloRunnable extends Thread
在inheritance方面,您可以使用Runnable做更多事情。
@BalwantChauhan:Runnable接口的一个常见用法是,我们知道在Java的情况下不可能进行多重inheritance。 现在假设您有一个场景,您希望扩展一个类,并且您还想实现线程。 因此,对于那些情况,如果我们继续使用Thread,那么就无法实现它。 例如:假设(在Java Swing的情况下),如果你想创建一个框架,并且你想要在那个框架类中实现线程,那么就不可能扩展JFrame和Thread类,所以在这种情况下我们扩展了JFrame和实现Runnable。
public class HelloFrame extends JFrame implements Runnable{ ... public void run(){ // thread code } ... }