Java-Thread Vs Runnable
当从这里读取线程和可运行线程之间的显著差异时,我遇到了一个差异,即:
扩展线程类时,每个线程都会创建唯一的对象并与之关联。其中as
实现runnable时,它将同一对象共享给多个线程。
有代码给出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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(); } } |
输出如下:
1 2 3 4 5 6 | ImplementsRunnable : Counter : 1 ImplementsRunnable : Counter : 2 ImplementsRunnable : Counter : 3 ExtendsThread : Counter : 1 ExtendsThread : Counter : 1 ExtendsThread : Counter : 1 |
号
它证明了上面给出的差异。我对下面给出的代码做了一点修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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); } } |
现在输出为:
1 2 3 4 5 6 | ImplementsRunnable : Counter : 1 ImplementsRunnable : Counter : 2 ImplementsRunnable : Counter : 3 ExtendsThread : Counter : 1 ExtendsThread : Counter : 2 ExtendsThread : Counter : 3 |
。
我了解这样一个事实,这里相同的对象(extendthread)由三个线程共享。但这里我很困惑,它与实现runnable有什么不同。在这里,即使*extendthread*扩展线程,我们仍然能够将这个类的对象共享给其他线程。在我看来,上述区别没有任何意义。
谢谢。
这是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:
号
所以这两种方法
1 2 3 4 5 6 7 8 9 10 | public class MyThread extends Thread { // overriden from Runnable, which Thread implements public void run() { ... } } ... MyThread thread = new MyThread(); thread.start(); |
号
或
1 2 3 4 5 6 7 8 |
您的
在第一种情况下,这里创建的每个对象
1 2 3 4 5 6 7 8 | 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(); |
。
将有自己的副本(这就是实例变量的工作方式)。因此,当您启动每个线程时,每个线程都会增加自己的字段副本。
在第二种情况下,您使用
1 2 3 4 5 6 7 8 9 10 |
它是您传递的同一个
从注释中添加:
首先要理解的是,
。
当使用
1 |
。
然后启动它,线程调用给定的
当你创建一个自定义线程
1 | new ExtendsThread(); |
一开始,它自己就给
实现runnable的主要区别在于,您不"消耗"单个继承。考虑这些类声明:
1 2 3 |
当涉及到继承时,您可以用runnable做更多的事情。
@ BalwantChauhan:Runnabl接口的一个常见用法是,我们知道,在Java的情况下,多重继承是不可能的。现在假设您有一个场景,您希望扩展一个类,并且还希望实现线程。所以对于这些场景,如果我们继续执行线程,那么就不可能实现它。例如:假设(在JavaSwing的情况下),如果要创建一个框架,并且在要实现线程的那个框架类中,则不可能扩展JFrand和Trand类,在这种情况下,我们扩展了JFrand并实现了RunnEnabl。
1 2 3 4 5 6 7 8 9 10 |
。