Java 线程与 Runnable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21871073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:11:14  来源:igfitidea点击:

Java-Thread Vs Runnable

javamultithreading

提问by Balwant Kumar Singh

While reading through the significant difference between Thread and Runnable from here, I encountered a difference that is:

这里阅读 Thread 和 Runnable 之间的显着差异时,我遇到了一个差异:

When you extends Thread class, each of your thread creates unique object and associate with it.where as

当您扩展 Thread 类时,您的每个线程都会创建唯一的对象并与之关联。然而

When you implement Runnable, it shares the same object to multiple threads..

当您实现 Runnable 时,它​​会将同一个对象共享给多个线程。.

There is code give :

有代码给:

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();
   }
 }

The output is something like this:

输出是这样的:

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

It proves differences given above. I make a slight modification in code given below:

它证明了上面给出的差异。我在下面给出的代码中稍作修改:

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);
  }
}

Now the output is :

现在输出是:

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 2
ExtendsThread : Counter : 3

I understand the fact that, here same object (extendsThread) is shared by three threads. But I'm confused here that how it is different from implementing Runnable. Here, even if *ExtendsThread *extends Thread, we are still able to share the object of this class to other threads. In my thinking the above difference does not make any sense.

我理解这样一个事实,这里同一个对象(extendsThread)由三个线程共享。但我在这里很困惑,它与实现 Runnable 有何不同。在这里,即使 * ExtendsThread *extends Thread ,我们仍然可以将这个类的对象共享给其他线程。在我看来,上述差异没有任何意义。

Thanks.

谢谢。

回答by jeremyjjbrown

The principle difference in implementing Runnable is that you do not 'consume' your single inheritance. Consider these Class declarations:

实现 Runnable 的主要区别在于您不“消耗”您的单一继承。考虑这些类声明:

public class HelloRunnable implements Runnable extends AbstractHello

public class HelloRunnable extends Thread

You can do more with Runnable when it comes to inheritance.

在继承方面,您可以使用 Runnable 做更多事情。

回答by Sotirios Delimanolis

Here's what the javadocstates

这是javadoc 的说明

There are two ways to create a new thread of execution.One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started. For example, a thread that computes primes larger than a stated value could be written as follows:

The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.The same example in this other style looks like the following:

两种方法可以创建新的执行线程。一种是将 类声明为 Thread 的子类。这个子类应该覆盖类 Thread 的 run 方法。然后可以分配和启动子类的实例。例如,计算大于规定值的素数的线程可以写成如下:

创建线程的另一种方法是声明一个实现 Runnable 接口的类。然后该类实现 run 方法。然后可以分配类的实例,在创建 Thread 时将其作为参数传递并启动。其他样式中的相同示例如下所示:

So the two ways

所以两种方式

public class MyThread extends Thread {
    // overriden from Runnable, which Thread implements
    public void run() {
        ...
    }
}

...
MyThread thread = new MyThread();
thread.start();

Or

或者

public class MyRunnable implements Runnable{
    public void run() {
        ...
    }
}
...
Thread thread = new Thread(new MyRunnable());
thread.start();

Your counterfield is an instance field.

您的counter字段是一个实例字段。

In your first case, each of the objects created here

在你的第一种情况下,这里创建的每个对象

 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();

will have their own copy (that's how instance variables work). So when you start each thread, each one increments its own copy of the field.

将有自己的副本(这就是实例变量的工作方式)。因此,当您启动每个线程时,每个线程都会增加自己的字段副本。

In your second case, you are using your Threadsub class as a Runnableargument to the Threadconstructor.

在第二种情况下,您使用Thread子类作为构造函数的Runnable参数Thread

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);

It is the same ExtendsThreadobject that you pass, so its counterfield gets incremented by all threads. It's pretty much equivalent to your previous usage of ImplementsRunnable.

它与ExtendsThread您传递的对象相同,因此counter所有线程都会增加其字段。它几乎等同于您之前对ImplementsRunnable.

To add from the comments:

从评论中添加:

First thing to understand is that the Threadclass implements Runnable, so you can use a Threadinstance anywhere you can use Runnable.For example,

首先要了解的是Thread该类实现了Runnable,因此您可以在Thread任何可以使用的地方使用实例Runnable例如,

new Thread(new Thread()); // won't do anything, but just to demonstrate

When you create a Threadwith

当你创建一个Thread

new Thread(someRunnable);

and start it, the thread calls the given Runnableinstance's run()method. If that Runnableinstance happens to also be an instance of Thread, so be it. That doesn't change anything.

并启动它,线程调用给定Runnable实例的run()方法。如果该Runnable实例恰好也是 的实例Thread,那就这样吧。这不会改变任何事情。

When you create a custom thread like

当您创建一个自定义线程时

new ExtendsThread();

and start it, it calls run()on itself.

并启动它,它会调用run()自己。

回答by Suneet Bansal

@BalwantChauhan: One common usage of Runnable interface is that as we know that multiple inheritance is not possible in case of Java. Now suppose you have a scenario where you want extends a class and also you want to implement thread. So for those scenario if we go ahead for Thread then it is not possible to achieve it. For example : Suppose (in case of Java Swing), if you want to create a frame and also in that frame class you want to implement thread, then it is not possible to extends JFrame and Thread class so in that case we extends JFrame and implement Runnable.

@BalwantChauhan:Runnable 接口的一种常见用法是,我们知道在 Java 的情况下不可能进行多重继承。现在假设你有一个场景,你想要扩展一个类,并且你想要实现线程。因此,对于那些场景,如果我们继续使用 Thread,则不可能实现它。例如:假设(在 Java Swing 的情况下),如果你想创建一个框架,并且你想在那个框架类中实现线程,那么就不可能扩展 JFrame 和 Thread 类,所以在这种情况下,我们扩展 JFrame 和实现可运行。

public class HelloFrame extends JFrame implements Runnable{

  ...

  public void run(){
    //  thread code
  }

  ...
}