`

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

    在spring boot中使用java线程池ExecutorService的讲解

    2. 提高系统的性能:线程池可以重复使用已经创建的线程,避免了频繁地创建和销毁线程,从而提高系统的性能。 线程池的组成部分 线程池包括以下四个基本组成部分: 1. 线程池管理器(ThreadPool):用于创建并管理...

    java线程和线程池的使用.docx

    在 Java 中,线程是程序执行的独立路径,它们允许应用程序并发执行多个任务。线程池则是一种管理线程的机制,它可以帮助我们更高效、更可控地使用线程资源。下面将详细介绍 Java 中线程的创建方式以及线程池的使用。...

    java 线程池

    ### Java线程池详解 ...Java线程池是一种高效、实用的多线程处理方案,它通过管理和复用一定数量的线程来避免频繁创建和销毁线程所带来的开销。正确配置和使用线程池对于提升程序的性能和稳定性具有重要意义。

    java多线程并发

    - **固定大小的线程池**:`newFixedThreadPool(int nThreads)`创建一个可重用的固定线程数量的线程池,这些线程按需创建,且可以重复使用。 ```java ExecutorService service = Executors.newFixedThreadPool(3);...

    java_Thread.rar_java 多线程_java多线程

    总之,Java多线程是Java程序员必须掌握的核心技能之一,它涉及到程序的并发性、性能优化以及资源管理等多个方面。通过"java_Thread.txt"这样的实例学习,可以帮助我们更好地理解和应用Java的多线程特性,提升我们的...

    Socket网络编程学习笔记之---使用线程池提高性能

    线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池可以有效地控制运行的线程数量,当线程数量过多时,可以适当控制新的线程的创建,避免过多线程导致系统资源的...

    Java多线程技术

    Java多线程技术是Java编程语言中的一个重要部分,它允许程序员创建多个线程来执行多个任务,这样可以有效地利用系统资源,提高程序的执行效率。在Java中,多线程的实现主要有两种方式:一种是继承Thread类,另一种是...

    Java多线程编程

    线程池是一种用于管理线程的技术,它可以重复使用预先创建的线程,而不是每次需要执行新任务时都创建新的线程。Java中的`ExecutorService`接口提供了创建和管理线程池的功能。 ##### 5.1 创建线程池 使用`Executors...

    Java多线程实现.pdf

    Java多线程编程是Java平台的核心特性之一,特别是在Java 5之后,其并发包`java.util.concurrent`的引入,极大地提升了开发多线程应用的效率和性能。本篇内容主要探讨了如何使用Java 5的并发工具来实现一个高效的网络...

    Java多线程文章系列.pdf

    #### 十一、实战Java多线程编程精要之高级支持 - **线程组**: - 用于管理和控制一组线程。 - **线程间发信**: - 实现线程间的通信。 - **屏蔽同步**: - 采用特定技术减少同步的使用。 - **守护线程**: - 守护...

    java线程入门级书籍

    线程池预先创建一定数量的线程,这些线程可以重复使用。当有新的任务提交给线程池时,线程池会从空闲线程中选择一个执行该任务。 ```java ExecutorService executor = Executors.newFixedThreadPool(5); executor....

    Java线程 学习

    - **线程池**:通过使用线程池,可以重复使用预创建的线程,减少创建和销毁线程的开销。常见的线程池类型包括`FixedThreadPool`、`CachedThreadPool`等。 #### 六、线程间的通信与同步 - **wait()、notify() 和 ...

    并发-线程池和阻塞队列.pdf

    线程池和阻塞队列是实现并发的关键组件之一。本文将详细介绍线程池原理、使用场景及注意事项,以及阻塞队列的相关知识。 首先,线程池是一种基于池化思想管理线程的技术,它可以重用一组线程执行多个任务。线程池的...

    java多线程几个概念

    ### Java多线程几个核心概念 #### 一、理解多线程 多线程是一种让程序内部的不同...总之,Java多线程是开发高性能应用程序的基础之一。掌握多线程的基本概念和技术,对于提高程序的并发能力和响应速度具有重要意义。

    Java多线程设计模式.pdf

    从给定的信息来看,文档标题和描述均指出是关于“Java多线程设计模式”的内容,但是提供的部分内容并未涉及实际的技术细节,而是重复了联系方式。因此,本篇将基于标题和描述来展开“Java多线程设计模式”的知识点...

    一个基于java的多线程爬虫项目.zip

    2. **多线程**:多线程是Java的核心特性之一,它允许程序同时执行多个任务。在爬虫项目中,多线程可以提高抓取网页的效率,每个线程负责处理不同的URL,加快整体爬取速度。 3. **网络编程**:Java的`java.net`包...

    多线程开发书籍

    2. **死锁**:多线程程序中最常见的问题之一。 - **预防措施**: - 避免嵌套锁定。 - 使用锁顺序或锁所有权的概念。 3. **饥饿**:某些线程可能因为优先级较低而始终无法获得执行机会。 - **解决方法**:合理...

    笔记-6、线程池1

    线程池是Java并发编程中一个重要的概念,它是一种多线程处理形式,通过维护一组可重用线程来减少创建和销毁线程的开销。线程池的使用可以有效控制运行的线程数量,避免因频繁创建和销毁线程而带来的性能损失。 1. ...

    【并发编程】如何优雅使用线程池.pdf

    ### 并发编程之线程池的优雅使用 #### 基本概念 在深入了解线程池之前,我们首先需要了解几个基本的概念。 - **进程**:是指正在运行的一个程序的实例,它拥有独立的地址空间,每个进程都有自己的状态(如运行、...

Global site tag (gtag.js) - Google Analytics