与 ExecutorService 保持计数器?
Keeping a counter with ExecutorService?
我想保留一个已执行线程的计数器,以在我正在执行的相同线程中使用。
这里的问题是,虽然计数器增加了,但增加不均匀,从控制台输出我得到了这个(我有一个 for 循环,使用 ExecutorService 执行 5 个线程):
This is a test. N:3
This is a test. N:4
This is a test. N:4
This is a test. N:4
This is a test. N:4
如您所见,我得到的不是 1,2,3,4,5
,而是 3,4,4,4,4
。
我假设这是因为 for 循环 运行 快到足以执行线程,并且线程快到足以执行请求计数器的代码,速度快于计数器更新自身的速度(是吗?甚至有意义?)。
这是代码(它比较小,对计数器没有任何意义):
for (int i = 0; i < 5; i++)
{
Thread thread;
thread = new Thread()
{
public void run()
{
System.out.println("This is test. N: "+aldo );
//In here there is much more stuff, saying it because it might slow down the execution (if that is the culprit?)
return;
}
};
threadList.add(thread);
}
//later
for (int i = 0; i < threadList.size(); i++)
{
executor.execute(threadList.get(i));
aldo = aldo + 1;
}
executor.shutdown();
try
{
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e)
{
}
是的,aldo
代码中缺少计数器(我认为还有一些其他列表)(它们非常简单)。
aldo
并没有被线程中的任务修改,而是在主线程中被修改,这里:
for (int i = 0; i < threadList.size(); i++) {
executor.execute(threadList.get(i));
//here...
aldo = aldo + 1;
}
此外,由于您想要一个可以在多个线程中增加其值的计数器,因此您可以使用 AtomicInteger
而不是 int
。
您的代码应如下所示:
AtomicInteger aldo = new AtomicInteger(1);
for (int i = 0; i < 5; i++) {
executor.execute( () -> {
System.out.println("This is test. N: " + aldo.getAndIncrement());
});
}
据我所知,最好的方法是创建自定义线程 class,并使用传入数字的构造函数。保存数字的变量稍后可以用于任何需要的日志记录。这是我想出的代码。
public static void main(String[] args) {
class NumberedThread implements Runnable {
private final int number;
public NumberedThread(int number) {
this.number = number;
}
@Override
public void run() {
System.out.println("This is test. N: " + number);
}
}
List<Thread> threadList = new ArrayList<>();
for (int i = 1; i < 6; i++) threadList.add(new Thread(new NumberedThread(i)));
ExecutorService executor = Executors.newFixedThreadPool(10);;
for (Thread thread : threadList) executor.execute(thread);
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException ignored) { }
}
如果您想为线程命名,也可以使用字符串对象。
我想保留一个已执行线程的计数器,以在我正在执行的相同线程中使用。
这里的问题是,虽然计数器增加了,但增加不均匀,从控制台输出我得到了这个(我有一个 for 循环,使用 ExecutorService 执行 5 个线程):
This is a test. N:3
This is a test. N:4
This is a test. N:4
This is a test. N:4
This is a test. N:4
如您所见,我得到的不是 1,2,3,4,5
,而是 3,4,4,4,4
。
我假设这是因为 for 循环 运行 快到足以执行线程,并且线程快到足以执行请求计数器的代码,速度快于计数器更新自身的速度(是吗?甚至有意义?)。
这是代码(它比较小,对计数器没有任何意义):
for (int i = 0; i < 5; i++)
{
Thread thread;
thread = new Thread()
{
public void run()
{
System.out.println("This is test. N: "+aldo );
//In here there is much more stuff, saying it because it might slow down the execution (if that is the culprit?)
return;
}
};
threadList.add(thread);
}
//later
for (int i = 0; i < threadList.size(); i++)
{
executor.execute(threadList.get(i));
aldo = aldo + 1;
}
executor.shutdown();
try
{
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e)
{
}
是的,aldo
代码中缺少计数器(我认为还有一些其他列表)(它们非常简单)。
aldo
并没有被线程中的任务修改,而是在主线程中被修改,这里:
for (int i = 0; i < threadList.size(); i++) {
executor.execute(threadList.get(i));
//here...
aldo = aldo + 1;
}
此外,由于您想要一个可以在多个线程中增加其值的计数器,因此您可以使用 AtomicInteger
而不是 int
。
您的代码应如下所示:
AtomicInteger aldo = new AtomicInteger(1);
for (int i = 0; i < 5; i++) {
executor.execute( () -> {
System.out.println("This is test. N: " + aldo.getAndIncrement());
});
}
据我所知,最好的方法是创建自定义线程 class,并使用传入数字的构造函数。保存数字的变量稍后可以用于任何需要的日志记录。这是我想出的代码。
public static void main(String[] args) {
class NumberedThread implements Runnable {
private final int number;
public NumberedThread(int number) {
this.number = number;
}
@Override
public void run() {
System.out.println("This is test. N: " + number);
}
}
List<Thread> threadList = new ArrayList<>();
for (int i = 1; i < 6; i++) threadList.add(new Thread(new NumberedThread(i)));
ExecutorService executor = Executors.newFixedThreadPool(10);;
for (Thread thread : threadList) executor.execute(thread);
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException ignored) { }
}
如果您想为线程命名,也可以使用字符串对象。