我很困惑(java新手):
在实现 Runnable 接口时,必须重写 run() 方法才能获得线程执行能力。实现此接口使您的对象成为 Runnable (?) 类型。如何通过简单地实现 Runnable 接口来“注入”线程功能?基本上,当您实例化一个实现 Runnable 的类时,线程功能中发生了什么?我可能在这里误解了一些基于 OO 的概念。谢谢。
是 JVM 在执行 thread.start() 时“知道”寻找可运行对象吗?
当您创建 的实现时Runnable
,没有任何东西将您的类与 JVM 的线程容量联系起来。接口的实例Runnable
就像任何其他接口的实例,只是另一个实例。
如果要使用 JVM 的线程系统,则必须使用Thread
该类的新实例,它将在单独的线程中运行实现的run()
方法。Runnable
所有关于创建新线程的逻辑都由Thread
类完成。
Runnable 表示“可以”在单独的线程中运行或不“可以”运行的工作(您可以自己调用 Runnable.run() )。
但是要在单独的线程中调用 Runnable 然后执行类似的操作
Thread thread = new Thread(new MyRunnable());
thread.start(); // MyRunnable will now be invoked in a new thread
在后台真的没有什么特别的事情发生。
实现Runnable
接口确保您的类将有一个public void run()
方法。
当您将自定义类传递给Thread
.
Thread th = new Thread(new YourCustomRunnable());
th.start();
在上面的代码中,Thread
会创建一个新的,run()
方法里面的代码会在另一个线程中运行。
在内部,线程将调用您的自定义run()
方法并使该代码在单独的线程上运行。在技术上可以做到以下几点:
Runnable r = new MyCustomRunnable();
r.run();
在上面的代码中,r
不会在单独的线程上运行。
实现 Runnable 不会启动一个新线程,要启动一个新线程,您需要创建一个新的 Thread 对象并启动它,并且 Thread 最常用的构造函数之一将 Runnable 作为参数(Thread(Runnable)):
Thread t = new Thread(new MyRunnable());
t.start();
实现 Runnable 不会神奇地让你的类在线程上运行。相反,您可以执行以下操作:
Runnable myRunnable = new MyRunnable(); // MyRunnable implements Runnable
Thread t = new Thread(myRunnable);
t.start();
现在您在 myRunnable 的 run() 方法中的代码将在单独的线程中执行。我建议您查看 java.util.concurrent 包中的 ExecutorService 和 Executors。这些对象将在线程中执行您传入(可运行)的内容。使用 Executor/ExecutorService 的优点是您可以预定义要分配的线程数,并采用各种策略来增长/收缩或保持不变。
新手感兴趣的另一件事:线程可以是守护程序(后台)或非守护程序(如 UI)线程。如果有非守护线程在运行,你的 JVM 不会死掉。要将线程声明为守护进程,只需调用 setDaemon()。对于执行程序,您需要提供一个 ThreadFactory,您可以在其中创建线程并将其标记为守护进程。
希望这可以帮助。
接口是一种契约。通过实现 Runnable,您承诺您将提供接口中定义的所有方法。因此,任何其他知道 Runnable.run() 的类(如“Thread”)都可以在您的类的对象上调用此方法。即使对你的班级一无所知。
为了使用您的代码启动一个新线程,您需要编写如下内容:
Thread thread = new Thread(new MyRunnable());
thread.start();
start() 方法将执行一些操作系统魔术以生成线程,然后在您作为参数提供给构造函数的对象上在该操作系统线程的上下文中调用 run() 方法。
就最近的定义(spring/DI)而言,没有“注入”。Runnable 与任何其他接口没有什么不同。它是一个“契约”,表明你的类提供了在接口中调用的任何必要的方法。