Java 中线程内的线程?

发布于 2024-12-01 17:35:06 字数 383 浏览 1 评论 0原文

我目前正在考虑如何用Java设计一个需要进行一些繁重的网络处理和数据库存储的多线程系统。该程序首先将启动三个基本线程。沿着这些基本线程,我想不是从主程序而是从两个线程启动其他线程。一个线程是否有可能启动另一个线程,从而导致某种层次结构,例如:

> Parent ->t0 thread1 -> t1 tread1.1  
>        ->t0 thread2
>        ->t0 thread3 -> t2 thread3.1

t0= inital time
t1,t2 = time at a point in the running thread
t1 != t2 

如果没有,有人可以提供带有参考的理论解决方案吗?

I am currently thinking about how to design a multithreading system in Java that needs to do some heavy network processing and database storage. The program will launch three basic threads at first. Along these basic threads, I would like to launch other threads not from the main program but from two of the threads. Is it possible for a thread to launch another thread leading to some sort of a hierarchy like:

> Parent ->t0 thread1 -> t1 tread1.1  
>        ->t0 thread2
>        ->t0 thread3 -> t2 thread3.1

t0= inital time
t1,t2 = time at a point in the running thread
t1 != t2 

If not could somebody provide a theoretical solution with references?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

落墨 2024-12-08 17:35:06

是的,您可以根据需要启动任意数量的线程,但这可能不是最好的方法。最好使用非阻塞 API,这样您就可以开始执行某些外部调用,并且调用线程可以立即开始执行其他操作,而无需等待套接字/数据库调用返回。然后,当套接字/数据库调用返回时,将触发回调以完成该处理。

非阻塞 I/O 可以提供更高的 CPU 利用率,因为您只需触发调用并注册回调,而不必尝试平衡“正确”数量的并发线程,而这些线程大多只是处于睡眠状态。

http://www.owlmountain.com/tutorials/NonBlockingIo.htm

http://www。 tensegrity.hellblazer.com/2008/03/non-blocking-jdbc-non-blocking-servlet-apis-and-other-high-mysteries.html

Yes, you can launch as many threads as you want, but that's probably not the best way to go. It's much better to use the non-blocking API's so that you can start execution of some external call and the calling thread can immediately start doing something else without waiting on the socket/database call to come back. Then, when the socket/database call comes back, a callback is triggered to finish that processing.

Non-blocking I/O can provide far superior CPU utilization since you're just triggering calls and registering callbacks and not having to try to balance the "right" number of concurrent threads which are mostly just sleeping anyways.

http://www.owlmountain.com/tutorials/NonBlockingIo.htm

http://www.tensegrity.hellblazer.com/2008/03/non-blocking-jdbc-non-blocking-servlet-apis-and-other-high-mysteries.html

沧笙踏歌 2024-12-08 17:35:06

To answer the question, yes threads can launch other threads.

Is the hierarchy important?

You're probably better off using an ExecutorService with a cached thread pool. That way you can pool threads instead of creating lots (which is expensive). ExecutorServices also provide other cool things, and using Callables / Runnables with them is probably much easier to test than mucking about with threads on your own.

薄情伤 2024-12-08 17:35:06

是的,一个线程可以启动另一个线程,并且该线程可以启动线程等等...

在线程的 run() 方法中 - 您可以创建并启动其他线程。

Yes a thread can launch another thread, and that thread can launch thread(s) and on and on...

In the run() method of a thread - you can create and start other threads.

两仪 2024-12-08 17:35:06

这是可能的
例如,您可以创建线程并将 id 放入数组中,如下所示

UnThread[] tab=   new  UnThread[10] ;

for ( int i=0;i<20;i++)

tab[i] = new UnThread();

供给 subMainThread 之后,

在您可以将数组选项卡提

  while( tab[1].isAlive() ) {
  //do somthing..
  System.out.println("Ligne affichée par le main");
  try {
    // et faire une pause
    tab[1].sleep(800);
  }
  catch (InterruptedException ex) {}
 }

这里是线程的简单使用示例:
http://kamel.berrayah.com/wordpress/2013/07/java-线程/

It's possible
for exemple you can creat thread and put id in array like this

UnThread[] tab=   new  UnThread[10] ;

for ( int i=0;i<20;i++)

tab[i] = new UnThread();

After you can give to the subMainThread the array tab

exemple

  while( tab[1].isAlive() ) {
  //do somthing..
  System.out.println("Ligne affichée par le main");
  try {
    // et faire une pause
    tab[1].sleep(800);
  }
  catch (InterruptedException ex) {}
 }

here a simple use of thread :
http://kamel.berrayah.com/wordpress/2013/07/java-threads/

萌面超妹 2024-12-08 17:35:06

ExecutorService

Java 5 带来了 Executors 框架。一些漂亮的接口和类将我们 Java 程序员从处理线程的乏味中解放出来。相反,我们可以将任务定义为 RunnableCallable,并将这些对象交给执行器服务,以便由任意数量的后台线程最终执行。

没有嵌套线程的示例

在讨论嵌套线程之前,让我们创建一个仅包含一层后台线程的示例。

我们使用单个 ExecutorService 运行三个线程,如您的问题所示。一个线程将执行一项简单的任务。另外两个线程将各自执行一项冗长的任务,其中包括一些网络处理,然后是一些数据库存储。

我们通过调用 Thread.sleep 来模拟冗长的工作。

class Hello implements Runnable
{
    @Override
    public void run ( )
    {
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 3 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Hello World! " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

然后我们实例化一些任务,第一个 Runnable 类的一个实例和第二个 Runnable 类的两个实例。

Collection < Runnable > tasks =
        List.of(
                new Hello( ) ,
                new NetworkProcessingAndDatabaseStorage( ) ,
                new NetworkProcessingAndDatabaseStorage( )
        );

接下来我们建立一个执行器服务来执行这些任务。 < code>Executors 实用程序类有许多方法可以使用具有各种行为的各种实现来实例化 ExecutorService

如今,我们通常应该使用执行器服务,为每个任务创建一个新的虚拟线程。虚拟线程“便宜”,因为它们比平台线程使用更少的内存和 CPU。从 Java 21 开始,虚拟线程是合适的。 22 如果您的任务满足三个条件:

  • 涉及阻塞(不受 CPU 限制)。例如,日志记录、网络调用、访问数据库、执行文件 I/O。
  • synchronized 块内没有长时间运行的代码。
  • 不通过JNI外部函数< /em>

重要提示:请注意 ExecutorService自动关闭。因此,我们可以使用 try-with-resources 语法来方便地等待所有提交的任务完成,然后自动关闭我们的执行器服务。

try (
        ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
)
{
    tasks.forEach( executorService :: submit );
}
// Flow of control blocks here, until all submitted tasks are done.

将这些代码放在一起。

package work.basil.example.threading;

import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NestedThreads
{
    public static void main ( String[] args )
    {
        NestedThreads app = new NestedThreads( );
        app.demo( );
    }

    private void demo ( )
    {
        long startNanos = System.nanoTime( );
        System.out.println( "INFO - Demo start. " + Instant.now( ) );

        // Instantiate some tasks to be executed.
        Collection < Runnable > tasks =
                List.of(
                        new Hello( ) ,
                        new NetworkProcessingAndDatabaseStorage( ) ,
                        new NetworkProcessingAndDatabaseStorage( )
                );

        // Submit those tasks to an executor service.
        try (
                ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
        )
        {
            tasks.forEach( executorService :: submit );
        }
        // Flow of control blocks here, until all submitted tasks are done.

        System.out.println( "INFO - Demo end. " + Instant.now( ) + ". Elapsed: " + Duration.ofNanos( System.nanoTime( ) - startNanos ) );
    }
}

class Hello implements Runnable
{
    @Override
    public void run ( )
    {
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 3 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Hello World! " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

运行时。注意经过的时间为 6 秒。

INFO - Demo start. 2024-07-21T22:42:47.964596Z
25 begins its `run` method. 2024-07-21T22:42:47.975005Z
24 begins its `run` method. 2024-07-21T22:42:47.975003Z
Hello World! 22 2024-07-21T22:42:50.978654Z
Did network processing. 25 2024-07-21T22:42:51.986931Z
Did network processing. 24 2024-07-21T22:42:51.987205Z
Did database storage. 24 2024-07-21T22:42:53.989489Z
Did database storage. 25 2024-07-21T22:42:53.989115Z
INFO - Demo end. 2024-07-21T22:42:53.990572Z. Elapsed: PT6.026181S

嵌套线程的示例

我们现在可以修改示例以使用嵌套线程。我们可以将每个 NetworkProcessingAndDatabaseStorage 任务作为子任务在另外两个线程上同时执行,而不是先执行网络访问,然后再执行数据库存储。

我们只需实例化更多 ExecutorService 对象就可以实现这一点。更改 NetworkProcessingAndDatabaseStorage 来实例化、使用和关闭执行程序服务。

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        try (
                ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
        )
        {
            executorService.submit( ( ) -> {
                // Simulate some lengthy work being done.
                try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
                System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
            } );
            executorService.submit( ( ) -> {
                // Simulate some lengthy work being done.
                try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
                System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
            } );
        }
        // Flow of control blocks here, until all submitted tasks are done.
    }
}

运行时,请注意运行时间如何从 6 秒缩短到 4 秒。它们不是网络处理花费 4 秒,数据库存储花费 2 秒,总共 6 秒,而是在多核机器上并行运行,总共 4 秒。

INFO - Demo start. 2024-07-21T22:59:57.207805Z
24 begins its `run` method. 2024-07-21T22:59:57.219105Z
23 begins its `run` method. 2024-07-21T22:59:57.219105Z
Did database storage. 30 2024-07-21T22:59:59.234550Z
Did database storage. 32 2024-07-21T22:59:59.235599Z
Hello World! 21 2024-07-21T23:00:00.224024Z
Did network processing. 31 2024-07-21T23:00:01.228877Z
Did network processing. 28 2024-07-21T23:00:01.228877Z
INFO - Demo end. 2024-07-21T23:00:01.230688Z. Elapsed: PT4.023049042S

ExecutorService

Java 5 brought the Executors framework. Some nifty interfaces and classes relieves us Java programmers from the tedium of juggling threads. Instead, we could define a task as a Runnable or Callable, and hand those objects over to an executor service for eventual execution by any number of background threads.

Example without nesting threads

Before getting to your nested threads, let's create an example with just one level of background threads.

We use a single ExecutorService to run three threads, as dictated by your Question. One thread will perform a simple tasks. Two other threads will each perform a lengthy task composed of some network processing and then some database storage.

We simulate the lengthy work by calling Thread.sleep.

class Hello implements Runnable
{
    @Override
    public void run ( )
    {
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 3 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Hello World! " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

Then we instantiate some tasks, one instance of the first Runnable class, and two instances of the second Runnable class.

Collection < Runnable > tasks =
        List.of(
                new Hello( ) ,
                new NetworkProcessingAndDatabaseStorage( ) ,
                new NetworkProcessingAndDatabaseStorage( )
        );

Next we establish an executor service to execute these tasks. The Executors utility class has many methods to instantiate an ExecutorService using various implementations with various behaviors.

Nowadays, we should generally use an executor service that creates a new virtual thread for each task. Virtual threads are "cheap" in that they use less memory and CPU than platform threads. A virtual thread is appropriate as of Java 21 & 22 if your task meets three criteria:

  • Involves blocking (not CPU-bound). For example, logging, network calls, accessing databases, doing file I/O.
  • Does not have long-running code within synchronized block.
  • Does not make long-running calls to native code via JNI or Foreign Functions.

Important: Note that ExecutorService is AutoCloseable. So, we can use try-with-resources syntax to conveniently wait until all submitted tasks are done, then automatically close our executor service.

try (
        ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
)
{
    tasks.forEach( executorService :: submit );
}
// Flow of control blocks here, until all submitted tasks are done.

Put that code together.

package work.basil.example.threading;

import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NestedThreads
{
    public static void main ( String[] args )
    {
        NestedThreads app = new NestedThreads( );
        app.demo( );
    }

    private void demo ( )
    {
        long startNanos = System.nanoTime( );
        System.out.println( "INFO - Demo start. " + Instant.now( ) );

        // Instantiate some tasks to be executed.
        Collection < Runnable > tasks =
                List.of(
                        new Hello( ) ,
                        new NetworkProcessingAndDatabaseStorage( ) ,
                        new NetworkProcessingAndDatabaseStorage( )
                );

        // Submit those tasks to an executor service.
        try (
                ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
        )
        {
            tasks.forEach( executorService :: submit );
        }
        // Flow of control blocks here, until all submitted tasks are done.

        System.out.println( "INFO - Demo end. " + Instant.now( ) + ". Elapsed: " + Duration.ofNanos( System.nanoTime( ) - startNanos ) );
    }
}

class Hello implements Runnable
{
    @Override
    public void run ( )
    {
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 3 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Hello World! " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
        // Simulate some lengthy work being done.
        try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
    }
}

When run. Notice an elapsed time of 6 seconds.

INFO - Demo start. 2024-07-21T22:42:47.964596Z
25 begins its `run` method. 2024-07-21T22:42:47.975005Z
24 begins its `run` method. 2024-07-21T22:42:47.975003Z
Hello World! 22 2024-07-21T22:42:50.978654Z
Did network processing. 25 2024-07-21T22:42:51.986931Z
Did network processing. 24 2024-07-21T22:42:51.987205Z
Did database storage. 24 2024-07-21T22:42:53.989489Z
Did database storage. 25 2024-07-21T22:42:53.989115Z
INFO - Demo end. 2024-07-21T22:42:53.990572Z. Elapsed: PT6.026181S

Example with nesting threads

We can now modify our example to make use of nested threads. Instead of each of our NetworkProcessingAndDatabaseStorage tasks doing the network access and then subsequently doing the database storage, we can do them both at the same time as subtasks on two more threads.

We can make this happen merely by instantiating more ExecutorService objects. Change the NetworkProcessingAndDatabaseStorage to instantiate, use, and close an executor service.

class NetworkProcessingAndDatabaseStorage implements Runnable
{
    @Override
    public void run ( )
    {
        System.out.println( Thread.currentThread( ).threadId( ) + " begins its `run` method. " + Instant.now( ) );
        try (
                ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ;
        )
        {
            executorService.submit( ( ) -> {
                // Simulate some lengthy work being done.
                try { Thread.sleep( Duration.ofSeconds( 4 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
                System.out.println( "Did network processing. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
            } );
            executorService.submit( ( ) -> {
                // Simulate some lengthy work being done.
                try { Thread.sleep( Duration.ofSeconds( 2 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
                System.out.println( "Did database storage. " + Thread.currentThread( ).threadId( ) + " " + Instant.now( ) );
            } );
        }
        // Flow of control blocks here, until all submitted tasks are done.
    }
}

When run, notice how the elapsed time collapses, going from 6 seconds to 4 seconds. Instead of the network-processing taking 4 seconds followed by the database-storage taking 2 seconds for a total of 6 seconds, they run in parallel on a multi-core machine, for a total of 4 seconds.

INFO - Demo start. 2024-07-21T22:59:57.207805Z
24 begins its `run` method. 2024-07-21T22:59:57.219105Z
23 begins its `run` method. 2024-07-21T22:59:57.219105Z
Did database storage. 30 2024-07-21T22:59:59.234550Z
Did database storage. 32 2024-07-21T22:59:59.235599Z
Hello World! 21 2024-07-21T23:00:00.224024Z
Did network processing. 31 2024-07-21T23:00:01.228877Z
Did network processing. 28 2024-07-21T23:00:01.228877Z
INFO - Demo end. 2024-07-21T23:00:01.230688Z. Elapsed: PT4.023049042S
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文