是否有一种方法可以限制同时运行的线程数量



我有一个对象列表List<EventuelleDestination> ev,我需要创建一个线程来序列化列表中每个元素的数据。但是,只允许同时运行3个线程。我对threadpool和其他类做了相当多的研究,但我仍然不知道如何在我的方法中实现这些限制。

如果它能有所帮助,下面是每个线程必须完成的任务,直到List被迭代。

public void serializeDestinationEmploye(EventuelleDestination e) {
Gson gson = new Gson();
String filename = "/" + employeDao.getEmploye().getId() + "_" + entrepriseDao.retrouveEmplacementIdParDepartementId(e.getEventuelAcceuillant().getId()) + "_" + e.getEventuelAcceuillant().getId() + ".json";
try {
Writer writer = new FileWriter(dossierSoumissions.toString() + filename);
new Gson().toJson(e, writer);
writer.close();
System.out.println(e + " has been serialized...");
} catch (IOException fileNotFoundException) {
fileNotFoundException.printStackTrace();
}
}

executor框架

Java 5带来了Executors框架,大大简化了线程工作。请参阅Chaudhuri的回答中的链接。

Runnable

将任务定义为RunnableCallable

package work.basil.example.threading;
import java.time.Instant;
import java.util.concurrent.ThreadLocalRandom;
public class Reporter implements Runnable
{
private Integer reportId;
public Reporter ( final Integer reportId )
{
this.reportId = reportId;
}
@Override
public void run ( )
{
// Simulate doing hard work by sleeping this thread a random number of milliseconds.
try { Thread.sleep( ThreadLocalRandom.current().nextInt( 5 , 100 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
String message = Thread.currentThread().getName() + " reporting id: " + this.reportId + " at " + Instant.now();
System.out.println( message );
}
}

ExecutorService

实例化一堆这样的任务。实例化由指定的三个线程支持的执行器服务。等待任务完成,关闭执行器服务。

package work.basil.example.threading;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
List < Reporter > tasks =
IntStream
.range( 100 , 200 )           // Generate a range of numbers from 100 through 199. 
.mapToObj( Reporter :: new )  // Method reference for the constructor of our `Reporter` class.
.toList();                    // Collect all the newly instantiated `Reporter` objects into a `List`. 
ExecutorService executorService = Executors.newFixedThreadPool( 3 ); // Hard-code to three, per the Stack Overflow Question's requirements.
tasks.stream().forEach( executorService :: submit );  // Submit to our executor service each of the collected tasks in our list.
this.shutdownAndAwaitTermination( executorService );
}
// Slightly modified version of boilerplate taken from Javadoc:
// https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html
void shutdownAndAwaitTermination ( ExecutorService executorService )
{
executorService.shutdown(); // Disable new tasks from being submitted
try
{
// Wait a while for existing tasks to terminate
if ( ! executorService.awaitTermination( 120 , TimeUnit.SECONDS ) )
{
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if ( ! executorService.awaitTermination( 120 , TimeUnit.SECONDS ) )
{ System.err.println( "Executor service did not terminate. " + Instant.now() ); }
}
}
catch ( InterruptedException ex )
{
// (Re-)Cancel if current thread also interrupted
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}

运行时:

pool-1-thread-2 reporting id: 101 at 2022-12-11T01:20:49.336052Z
pool-1-thread-1 reporting id: 100 at 2022-12-11T01:20:49.342575Z
pool-1-thread-3 reporting id: 102 at 2022-12-11T01:20:49.350614Z
pool-1-thread-2 reporting id: 103 at 2022-12-11T01:20:49.371866Z
pool-1-thread-1 reporting id: 104 at 2022-12-11T01:20:49.392103Z
pool-1-thread-2 reporting id: 106 at 2022-12-11T01:20:49.430291Z
pool-1-thread-3 reporting id: 105 at 2022-12-11T01:20:49.437875Z
pool-1-thread-3 reporting id: 109 at 2022-12-11T01:20:49.450208Z
pool-1-thread-3 reporting id: 110 at 2022-12-11T01:20:49.478506Z
pool-1-thread-1 reporting id: 107 at 2022-12-11T01:20:49.488794Z
pool-1-thread-1 reporting id: 112 at 2022-12-11T01:20:49.501638Z
pool-1-thread-2 reporting id: 108 at 2022-12-11T01:20:49.512510Z
pool-1-thread-3 reporting id: 111 at 2022-12-11T01:20:49.516905Z
pool-1-thread-1 reporting id: 113 at 2022-12-11T01:20:49.602825Z
pool-1-thread-2 reporting id: 114 at 2022-12-11T01:20:49.614678Z
pool-1-thread-3 reporting id: 115 at 2022-12-11T01:20:49.621172Z
pool-1-thread-1 reporting id: 116 at 2022-12-11T01:20:49.659485Z
pool-1-thread-2 reporting id: 117 at 2022-12-11T01:20:49.668028Z
pool-1-thread-3 reporting id: 118 at 2022-12-11T01:20:49.715350Z
pool-1-thread-2 reporting id: 120 at 2022-12-11T01:20:49.740292Z
pool-1-thread-1 reporting id: 119 at 2022-12-11T01:20:49.740722Z
pool-1-thread-2 reporting id: 122 at 2022-12-11T01:20:49.765576Z
pool-1-thread-3 reporting id: 121 at 2022-12-11T01:20:49.779553Z
pool-1-thread-2 reporting id: 124 at 2022-12-11T01:20:49.801574Z
pool-1-thread-1 reporting id: 123 at 2022-12-11T01:20:49.833277Z
pool-1-thread-3 reporting id: 125 at 2022-12-11T01:20:49.838785Z
pool-1-thread-2 reporting id: 126 at 2022-12-11T01:20:49.861583Z
pool-1-thread-1 reporting id: 127 at 2022-12-11T01:20:49.884080Z
pool-1-thread-2 reporting id: 129 at 2022-12-11T01:20:49.895801Z
pool-1-thread-3 reporting id: 128 at 2022-12-11T01:20:49.922937Z
pool-1-thread-1 reporting id: 130 at 2022-12-11T01:20:49.922936Z
pool-1-thread-2 reporting id: 131 at 2022-12-11T01:20:49.927722Z
pool-1-thread-1 reporting id: 133 at 2022-12-11T01:20:49.978305Z
pool-1-thread-3 reporting id: 132 at 2022-12-11T01:20:50.000371Z
pool-1-thread-2 reporting id: 134 at 2022-12-11T01:20:50.025637Z
pool-1-thread-1 reporting id: 135 at 2022-12-11T01:20:50.025969Z
pool-1-thread-1 reporting id: 138 at 2022-12-11T01:20:50.078081Z
pool-1-thread-3 reporting id: 136 at 2022-12-11T01:20:50.089295Z
pool-1-thread-2 reporting id: 137 at 2022-12-11T01:20:50.116680Z
pool-1-thread-3 reporting id: 140 at 2022-12-11T01:20:50.142114Z
pool-1-thread-2 reporting id: 141 at 2022-12-11T01:20:50.144543Z
pool-1-thread-2 reporting id: 143 at 2022-12-11T01:20:50.173864Z
pool-1-thread-1 reporting id: 139 at 2022-12-11T01:20:50.177693Z
pool-1-thread-1 reporting id: 145 at 2022-12-11T01:20:50.193305Z
pool-1-thread-3 reporting id: 142 at 2022-12-11T01:20:50.213100Z
pool-1-thread-2 reporting id: 144 at 2022-12-11T01:20:50.258059Z
pool-1-thread-1 reporting id: 146 at 2022-12-11T01:20:50.281883Z
pool-1-thread-3 reporting id: 147 at 2022-12-11T01:20:50.295357Z
pool-1-thread-2 reporting id: 148 at 2022-12-11T01:20:50.297879Z
pool-1-thread-3 reporting id: 150 at 2022-12-11T01:20:50.310537Z
pool-1-thread-2 reporting id: 151 at 2022-12-11T01:20:50.334702Z
pool-1-thread-1 reporting id: 149 at 2022-12-11T01:20:50.366817Z
pool-1-thread-2 reporting id: 153 at 2022-12-11T01:20:50.388458Z
pool-1-thread-1 reporting id: 154 at 2022-12-11T01:20:50.410089Z
pool-1-thread-3 reporting id: 152 at 2022-12-11T01:20:50.410866Z
pool-1-thread-2 reporting id: 155 at 2022-12-11T01:20:50.438706Z
pool-1-thread-2 reporting id: 158 at 2022-12-11T01:20:50.457866Z
pool-1-thread-3 reporting id: 157 at 2022-12-11T01:20:50.483979Z
pool-1-thread-1 reporting id: 156 at 2022-12-11T01:20:50.509379Z
pool-1-thread-2 reporting id: 159 at 2022-12-11T01:20:50.528403Z
pool-1-thread-1 reporting id: 161 at 2022-12-11T01:20:50.528355Z
pool-1-thread-3 reporting id: 160 at 2022-12-11T01:20:50.540466Z
pool-1-thread-3 reporting id: 164 at 2022-12-11T01:20:50.553258Z
pool-1-thread-3 reporting id: 165 at 2022-12-11T01:20:50.563534Z
pool-1-thread-1 reporting id: 163 at 2022-12-11T01:20:50.573721Z
pool-1-thread-3 reporting id: 166 at 2022-12-11T01:20:50.611714Z
pool-1-thread-2 reporting id: 162 at 2022-12-11T01:20:50.630698Z
pool-1-thread-1 reporting id: 167 at 2022-12-11T01:20:50.647767Z
pool-1-thread-3 reporting id: 168 at 2022-12-11T01:20:50.704881Z
pool-1-thread-2 reporting id: 169 at 2022-12-11T01:20:50.706819Z
pool-1-thread-1 reporting id: 170 at 2022-12-11T01:20:50.738498Z
pool-1-thread-2 reporting id: 172 at 2022-12-11T01:20:50.761919Z
pool-1-thread-1 reporting id: 173 at 2022-12-11T01:20:50.789843Z
pool-1-thread-2 reporting id: 174 at 2022-12-11T01:20:50.800720Z
pool-1-thread-3 reporting id: 171 at 2022-12-11T01:20:50.800720Z
pool-1-thread-3 reporting id: 177 at 2022-12-11T01:20:50.812244Z
pool-1-thread-1 reporting id: 175 at 2022-12-11T01:20:50.819188Z
pool-1-thread-2 reporting id: 176 at 2022-12-11T01:20:50.856135Z
pool-1-thread-1 reporting id: 179 at 2022-12-11T01:20:50.865442Z
pool-1-thread-1 reporting id: 181 at 2022-12-11T01:20:50.875508Z
pool-1-thread-3 reporting id: 178 at 2022-12-11T01:20:50.908384Z
pool-1-thread-2 reporting id: 180 at 2022-12-11T01:20:50.911297Z
pool-1-thread-3 reporting id: 183 at 2022-12-11T01:20:50.922288Z
pool-1-thread-2 reporting id: 184 at 2022-12-11T01:20:50.934034Z
pool-1-thread-1 reporting id: 182 at 2022-12-11T01:20:50.947619Z
pool-1-thread-3 reporting id: 185 at 2022-12-11T01:20:50.955411Z
pool-1-thread-1 reporting id: 187 at 2022-12-11T01:20:50.973815Z
pool-1-thread-3 reporting id: 188 at 2022-12-11T01:20:50.980241Z
pool-1-thread-1 reporting id: 189 at 2022-12-11T01:20:50.989099Z
pool-1-thread-2 reporting id: 186 at 2022-12-11T01:20:51.037188Z
pool-1-thread-3 reporting id: 190 at 2022-12-11T01:20:51.067505Z
pool-1-thread-2 reporting id: 192 at 2022-12-11T01:20:51.083379Z
pool-1-thread-1 reporting id: 191 at 2022-12-11T01:20:51.092831Z
pool-1-thread-1 reporting id: 195 at 2022-12-11T01:20:51.099644Z
pool-1-thread-2 reporting id: 194 at 2022-12-11T01:20:51.110563Z
pool-1-thread-3 reporting id: 193 at 2022-12-11T01:20:51.110563Z
pool-1-thread-2 reporting id: 197 at 2022-12-11T01:20:51.153739Z
pool-1-thread-3 reporting id: 198 at 2022-12-11T01:20:51.194933Z
pool-1-thread-1 reporting id: 196 at 2022-12-11T01:20:51.201879Z
pool-1-thread-2 reporting id: 199 at 2022-12-11T01:20:51.205119Z

请注意,输出到System.out不一定按时间顺序出现在控制台上。如果您关心,请始终包含时间戳,如Instant.now

所有这些都已经在Stack Overflow上讨论过了。

生成三个线程并让它们完成工作,从队列中获取任务。不会有比你生成的线程数更多的线程来处理任务。

但是更简单的方法是使用Java标准类ThreadPoolExecutor,它为您处理线程生成和池管理。

在https://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html

有一个很好的关于执行器的教程。

是否有办法限制同时运行的线程数

不直接,不。没有线程调度器钩子来做这种事情。

你实际的选择是创建一个3个线程的池:

  • ,,
  • 使用有界线程池的ExecutorService,或者
  • 使用第三方线程池库。

然后安排任务通过队列分发给池中的线程。

fww:ExecutorService方法是最简单的,因为它同时处理线程池管理和任务队列。详情请参阅其他答案


如果您没有3个线程的硬性要求,另一个可能的选择是使用Streamparallel步骤。这将使用JVM的公共fork-join池1并行执行任务。问题是您不能直接控制池的大小,并且其他任务可能会为该池排队。此外,在fork-join池中执行阻塞I/O可能会对使用公共池的应用程序部分造成问题;参见javadoc. ForkJoinPool .

理论上,可以为每个任务创建一个线程,并编写使用(例如)共享Semaphore的任务,以限制在任何给定时间运行任务的线程数量。但是创建线程是昂贵的,并且它们使用大量的内存(即使当它们被阻塞时),所以这不是一个实际的解决方案。


1 -这是当前实现的方式。我敢说,这在javadoc…

中没有说明。

相关内容

  • 没有找到相关文章

最新更新