Java线程与可运行线程
在阅读Thread和Runnable from之间的显著差异时,我遇到了一个差异: 扩展线程类时,每个线程都会创建唯一的对象并与之关联。其中 实现Runnable时,它将同一对象共享给多个线程。 有以下代码:Java线程与可运行线程,java,multithreading,Java,Multithreading,在阅读Thread和Runnable from之间的显著差异时,我遇到了一个差异: 扩展线程类时,每个线程都会创建唯一的对象并与之关联。其中 实现Runnable时,它将同一对象共享给多个线程。 有以下代码: class ImplementsRunnable implements Runnable { private int counter = 0; public void run() { counter++; System.out.println("Implemen
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
它证明了上面给出的差异。我对下面给出的代码做了一点修改:
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
我理解的事实是,在这里,同一个对象(extendstread)由三个线程共享。但我很困惑,它与实现Runnable有什么不同。在这里,即使*extendstread*扩展了Thread,我们仍然能够将这个类的对象共享给其他线程。在我看来,上述差异没有任何意义
谢谢。实现Runnable的主要区别在于您不会“消费”您的单一继承。考虑这些类声明:
public class HelloRunnable implements Runnable extends AbstractHello
public class HelloRunnable extends Thread
在继承方面,您可以使用Runnable做更多的工作。以下是状态
有两种方法可以创建新的执行线程。一种是
将类声明为线程的子类。这个子类应该
重写类Thread的run方法。子类的实例
然后可以分配和启动。例如,计算
大于规定值的素数可以写为:
创建线程的另一种方法是声明一个实现
可运行接口。然后该类实现run方法。一
然后可以分配类的实例,并将其作为参数传递
创建线程时启动。另一个中的示例与此相同
样式如下所示:
所以这两种方式
public class MyThread extends Thread {
// overriden from Runnable, which Thread implements
public void run() {
...
}
}
...
MyThread thread = new MyThread();
thread.start();
或
您的计数器
字段是一个实例字段
在第一种情况下,这里创建的每个对象
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();
将有自己的副本(这就是实例变量的工作方式)。因此,当您启动每个线程时,每个线程都会增加它自己的字段副本
在第二种情况下,使用线程
子类作为线程
构造函数的可运行
参数。
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);
它与您传递的extendedsthread
对象相同,因此它的计数器
字段由所有线程递增。它相当于您以前使用的ImplementsRunnable
从评论中添加:
首先要了解的是线程
类实现了可运行
,因此您可以在任何可以使用可运行
的地方使用线程
实例
new Thread(new Thread()); // won't do anything, but just to demonstrate
使用创建线程时
new Thread(someRunnable);
然后启动它,线程调用给定的Runnable
实例的run()
方法。如果该Runnable
实例恰好也是Thread
的实例,那么就这样吧。这不会改变任何事情
创建自定义线程时,如
new ExtendsThread();
然后启动它,它在自身上调用
run()
。@BalwantChauhan:Runnable接口的一个常见用法是,正如我们所知,在Java的情况下,多重继承是不可能的。现在假设您有一个场景,您希望扩展一个类,并且还希望实现线程。所以对于那些场景,如果我们继续线程,那么就不可能实现它。
例如:假设(在JavaSwing的情况下),如果您想要创建一个框架,并且在该框架类中您想要实现thread,那么扩展JFrame和thread类是不可能的,所以在这种情况下,我们扩展JFrame并实现Runnable
public class HelloFrame extends JFrame implements Runnable{
...
public void run(){
// thread code
}
...
}
@helderdarocha这是作为解决方案给出的。Rupesh Yadav和zEro之间存在冲突。我只是想知道,上面的区别有什么意义呢?困惑来自你的源头;实现runnable时,可以在线程之间共享对象。但你很少会这么做。你也可以用一个线程来做这件事,因为它无论如何都是可运行的,但那会更奇怪。@Sotirious Delimanolis所以,上面的区别是不相关的???@Balwantchouhan你能澄清一下你指的是哪一个上面的区别吗?@Sotirious Delimanolis当然。也就是说,当您扩展Thread类时,每个线程都会创建唯一的对象并与之关联。当您实现Runnable时,它与多个线程共享同一个对象。@BalwantChauhan首先要了解的是
Thread
类实现了Runnable
,因此您可以在任何可以使用Runnable
的地方使用Thread
实例。当您使用新线程(someRunnable)
创建线程
并启动它时,该线程将执行给定的Runnable
实例的run()
方法。如果该Runnable
实例恰好也是Thread
的实例,那么就这样吧,这不会改变任何事情。当您创建一个自定义线程(如new extendstread()
并启动它时,它会对自身调用run()
。@SotiriosDelimanolis我能说,通过将线程引用作为参数传递,它只是将旧实例的值复制到新实例吗?因此,输出为1,2,3
public class HelloFrame extends JFrame implements Runnable{
...
public void run(){
// thread code
}
...
}