`

Java之多线程之线程池之线程重复使用

阅读更多
一、问题背景

在使用多线程时,如果要开启一个任务,则就需要新建一个线程。
线程也是对象,那么是否可以不用新建,而使用原来的呢?

试试下面的方法:


        Thread incT = new Thread(new Inc(c));
        Thread decT = new Thread(new Dec(c));
        
        
        for(int i= 0; i < 200; i++){
            incT.start();
            System.out.println("incT:" + incT.getName());
            decT.start();
            System.out.println("decT:" + decT.getName());
        }



结果报错了:
Exception in thread "main" java.lang.IllegalThreadStateException

原因:
线程在执行完 start() 方法后,就会自动销毁。

二、如何解决线程重用

1、分析
每一个 Thread 的类都有一个 start 方法。
Thread 的 start 方法是这样描述的:

Causes this thread to begin execution;
the Java Virtual Machine calls the run method of this thread.
启动线程。Java虚拟机会调用该类的 run 方法。

那么该类的 run() 方法中就是调用了 Runnable 对象的 run() 方法。

2、解决
我们可以继承重写 Thread 类,在其 start 方法中添加不断循环调用传递过来的 Runnable 对象。
这就是线程池的实现原理。循环方法中不断获取 Runnable 是用 Queue 实现的,在获取下一个 Runnable 之前可以是阻塞的。


三、问题出处

Question: java thread reuse

I have always read that creating threads is expensive. I also know that you cannot rerun a thread.

I see in the doc of Executors class: Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.

Mind the word 'reuse'.

How do thread pools 'reuse' threads?


------------
Answer:

I think I understood what is confuzzabling you so here's my longer answer: the terminology is a tiny bit misleading (obviously, or you wouldn't ask that question specifically putting the emphasis on 'reuse'):

How do thread pools 'reuse' threads?

What is happening is that a single thread can be used to process several tasks (typically passed as Runnable, but this depend on your 'executor' framework: the default executors accepts Runnable, but you could write your own "executor" / thread-pool accepting something more complex than a Runnable [like, say, a CancellableRunnable]).

Now in the default ExecutorService implementation if a thread is somehow terminated while still in use, it is automatically replaced with a new thread, but this is not the 'reuse' they're talking about. There is no "reuse" in this case.

So it is true that you cannot call start() on a Java Thread twice but you can pass as many Runnable as you want to an executor and each Runnable's run() method shall be called once.

You can pass 30 Runnable to 5 Java Thread and each worker thread may be calling, for example, run() 6 times (practically there's not guarantee that you'll be executing exactly 6 Runnable per Thread but that is a detail).

In this example start() would have been called 6 times. Each one these 6 start() will call exactly once the run() method of each Thread:

From Thread.start() Javadoc:

* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.

BUT then inside each Thread's run() method Runnable shall be dequeued and the run() method of each Runnable is going to be called. So each thread can process several Runnable. That's what they refer to by "thread reuse".

One way to do your own thread pool is to use a blocking queue on to which you enqueue runnables and have each of your thread, once it's done processing the run() method of a Runnable, dequeue the next Runnable (or block) and run its run() method, then rinse and repeat.

I guess part of the confusion (and it is a bit confusing) comes from the fact that a Thread takes a Runnable and upon calling start() the Runnable 's run() method is called while the default thread pools also take Runnable.


-
Thread pool threads are basically running loops that pull submitted tasks off of a queue. The threads do not stop executing when they service a task, they just wait for the next one to be submitted to the queue. They never get 'rerun' as asked in the question, as they are just constantly running.

-


The run method of threads in a thread pool does not consist only of running a single task.
The run method of a thread in a thread pool contains a loop.
It pulls a task off of a queue, executes the task (which returns back to the loop when it is complete), and then gets the next task.

The run method doesn't complete until the thread is no longer needed.

Here is the run method of the Worker inner class in ThreadPoolExecutor.

696:         /**
697:          * Main run loop
698:          */
699:         public void run() {
700:             try {
701:                 Runnable task = firstTask;
702:                 firstTask = null;
703:                 while (task != null || (task = getTask()) != null) {
704:                     runTask(task);
705:                     task = null; // unnecessary but can help GC
706:                 }
707:             } finally {
708:                 workerDone(this);
709:             }
710:         }


-

It's not actually unnecessary - the (strange) test for task!=null in the loop makes it necessary to prevent continually processing the same task. Even if the loop were more conventional nulling task would be good because otherwise if getTask() blocks for a long time, the GC of task would otherwise be delayed for the same length of time.








-















-
http://stackoverflow.com/questions/2324030/java-thread-reuse



分享到:
评论

相关推荐

    线程池管理多线程上传

    线程池管理和多线程上传是并发编程中的一个重要实践,特别是在大数据传输和网络服务中。在Java等编程语言中,线程池通过有效地管理和复用线程资源,避免了频繁创建和销毁线程带来的开销,提升了系统性能。下面将详细...

    JAVA使用线程池查询大批量数据

    除了`ThreadPoolExecutor`,Java还提供了`Executors`工具类,它提供了一些预设的线程池配置,如`newFixedThreadPool`(固定大小线程池)、`newSingleThreadExecutor`(单线程线程池)等,方便开发者快速创建线程池。...

    java多线程查询数据库

    综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。

    java多线程、并发及线程池介绍收藏的几篇文档

    Java多线程、并发以及线程池是Java编程中至关重要的概念,特别是在处理高并发、高性能的系统设计时。以下是对这些主题的详细说明: 1. **Java 程序中的多线程** - 多线程允许一个程序同时执行多个任务,提高程序...

    java多线程分页查询

    ### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...

    常用多线程模板与鱼刺类多线程线程池应用小例子

    本篇文章将详细探讨“常用多线程模板”以及“鱼刺类(Fork/Join框架)多线程线程池”的应用,结合具体的代码实例来帮助理解这些概念。 首先,多线程是指在一个程序中同时执行多个不同的线程,以实现并行处理。在...

    Java中多线程的使用线程池.docx

    Java中的线程池是多线程编程中一种高效、可管理的执行机制。它通过预先创建并维护一组线程,避免了频繁地创建和销毁线程带来的开销,从而提高了程序的性能和响应速度。线程池的核心概念包括以下几个方面: 1. **...

    java多线程,对多线程,线程池进行封装,方便使用

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,我们可以通过实现Runnable接口或继承Thread类来创建线程。然而,直接使用线程可能存在一些问题,如资源管理...

    java线程、线程池、xml解析入门

    在学习这些知识时,初学者可以通过创建简单的多线程程序来实践,比如实现一个生产者消费者模型,或者利用线程池处理并发请求。对于XML解析,可以尝试读取和解析配置文件,或者通过XML与Java对象之间的绑定进行数据...

    Java多线程Executors批量执行数据实现限流

    Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...

    Java多线程编程,生命游戏,用线程池.zip

    Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多...

    java线程池使用后到底要关闭吗

    因为线程池中仍然有很多线程在运行,占用系统资源,导致内存泄露和应用崩溃。 通过实例代码,我们可以看到,如果不关闭线程池,可能会导致内存泄露和应用崩溃。在代码中,我们创建了一个线程池,然后执行一个打印...

    Java8并行流中自定义线程池操作示例

    这些流可以提高执行性能,以牺牲多线程的开销为代价。在这篇短文中,我们将看一下 Stream API的最大限制,同时看一下如何让并行流和线程池实例(ThreadPool instance)一起工作。 知识点:Java8引入了流的概念,流是...

    Java多线程下载网络图片

    总之,"Java多线程下载网络图片"这个案例涵盖了多线程编程的多个核心知识点,包括线程创建、同步机制、线程池管理和异常处理等。通过实践这些技术,开发者可以编写出更加高效、稳定、健壮的并发程序。

    java多线程实现大批量数据导入源码

    总的来说,本项目通过Java多线程技术,结合合理的数据切分和线程池管理,实现对大数据的高效批量处理。通过分析和优化这些关键点,我们可以根据实际情况调整参数,进一步提高数据导入导出的效率。

    Java多线程+线程池.docx

    Java 多线程和线程池 Java 多线程是指在 Java 编程语言中,一个线程的动态执行过程。这个过程包括线程的创建、执行和销毁三个阶段。在 Java 中,创建线程有多种方式,包括通过实现 Runnable 接口、继承 Thread 类...

    java多线程教程之如何使用线程池详解

    Java 多线程教程之如何使用线程池详解 Java 多线程教程中,线程池是一种非常重要的概念。在 Java 中,线程池是指一个线程的集合,可以重复使用这些线程来执行任务。使用线程池可以提高服务器的性能和可扩展性。本文...

    Java多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池)

    Java 多线程(Synchronized+Volatile+JUC 并发工具原理+线程状态+CAS+线程池) Java 多线程是 Java 语言中的一种并发编程机制,允许程序同时执行多个线程,以提高程序的执行效率和响应速度。 Java 多线程机制提供了...

    java多线程学习笔记之自定义线程池

    Java多线程学习笔记之自定义线程池 本篇文章主要介绍了Java多线程学习笔记之自定义线程池,通过深入了解ThreadPoolExecutor这个核心类,我们可以自定义线程池,满足不同的线程池需求。 Java多线程学习笔记之自定义...

Global site tag (gtag.js) - Google Analytics