虽然有类似的问题,但我找不到任何类似的例子,就像我得到的那样。我非常感谢任何帮助,了解我的实施错误。
我正在尝试做什么:
我有一个Main class Driver
,它可以实例化未知数量的线程。每个线程调用一个singleton
类,该类应模拟“假”文件传输操作。
我遇到的问题是,无论并发请求的数量是多少,我都需要将并发传输限制为2次传输。
我尝试解决问题的方法是在Thread
中添加每个新ConcurrentLinkedQueue
并使用Executors.newFixedThreadPool(POOL_SIZE)
管理它以将并发线程限制为2.对于每个交互 - 我使用pool.submit
从池中轮询新线程。
我遇到的问题是我的输出是这样的: [Thread1],[Thread1,Thread2],[Thread1,Thread2,Thread3] ......
虽然它应该是: [Thread1,Thread2],[Thread3,Thread4]
为何限制在这里不起作用?
复印机 - 这是我的singleton
课程。
public class Copier {
private final int POOL_SIZE = 2;
private static volatile Copier instance = null;
private Queue<Reportable> threadQuere = new ConcurrentLinkedQueue();
private static FileCopier fileCopier = new FileCopier();
private Copier() {
}
public static Copier getInstance() {
if (instance == null) {
synchronized (Copier.class) {
if (instance == null) {
instance = new Copier();
}
}
}
return instance;
}
public void fileTransfer(Reportable reportable) {
threadQuere.add(reportable);
ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
for (int i=0; i < threadQuere.size(); i++) {
System.out.println("This is the " + (i+1) + " thread");
pool.submit(new CopyThread());
}
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CopyThread - 代表一个线程类
public class CopyThread implements Reportable, Runnable {
private static FileCopier fileCopier = new FileCopier();
@Override
public void report(String bitrate) {
System.out.println(bitrate);
}
@Override
public void run() {
synchronized(fileCopier) {
long startTime = System.nanoTime();
long bytes = fileCopier.copyFile();
long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / 1000000000; // get in seconds
double bytesInMegas = (double) bytes / 1000000;
report(bytesInMegas + "MB were transferred in " + duration + " seconds");
}
}
}
驱动程序 - 我的main
类我在哪里创建所有线程
public class Driver {
public static void main(String[] args) {
Copier copier = Copier.getInstance();
CopyThread copyThread1 = new CopyThread();
CopyThread copyThread2 = new CopyThread();
CopyThread copyThread3 = new CopyThread();
CopyThread copyThread4 = new CopyThread();
copier.fileTransfer(copyThread1);
copier.fileTransfer(copyThread2);
copier.fileTransfer(copyThread3);
copier.fileTransfer(copyThread4);
int q = 0;
}
}
答案 0 :(得分:2)
一个更简单的解决方案是Semaphore,有2个许可。
这确保“外部”线程也不能绕过限制,因为您的解决方案期望同时任务受到线程池大小的限制。
当单个工具就足够时,您的解决方案会使用多个并发工具。您的DCL单例也有点过时了。
答案 1 :(得分:2)
这里的一切都很好(虽然有点奇怪)。您在提交之前打印线程编号,您需要做的是将print放在run方法中,您将看到一切正常。打印件都会正常关闭,因为您使用打印的区域与Executors无关。您的代码存在更多问题,但我认为您只是为了测试/学习而做了所有这些,这就是为什么它就是这样。
在这种情况下,就像我说的那样,将print放在run方法中(你可以在CopyThread类中使用一些静态变量来计算线程)。您的输出将类似于2个关于线程编号(1和2)的打印,2个打印关于传输所花费的时间,然后打印关于线程3和4(我说可能,因为我们正在使用线程,不能确定任何事情) - 当你的fileTransfer
提交4个runnables时,所有这一切都在第4步。您的单例已过时,因为它使用双重检查锁定,这在多线程计算机上是错误的,请检查:here。这不会破坏你的程序,所以以后会担心它。关于其他一切(奇怪的队列使用,fileTransfer
方法制作新的线程池等)就像我说的那样,它可能用于学习,但如果不是 - 你的队列也可能被删除,你只是用它来计算这样的计数可以通过一些计数器变量来完成,你的fileTransfer
方法应该只提交新的runnable到pool(这将是实例变量)来传输文件,而不是创建池并提交一些runnables,它有点像,直观。
编辑:检查一下,为了简单起见,我把全部放在Cat.java
中,改变了一些我不得不改变的东西(我没有FileCopier
类等等,但是你的问题答案就在这里):
import java.util.*;
import java.util.concurrent.*;
class Copier {
private final int POOL_SIZE = 2;
private static volatile Copier instance = null;
private Copier() {
}
public static Copier getInstance() {
if (instance == null) {
synchronized (Copier.class) {
if (instance == null) {
instance = new Copier();
}
}
}
return instance;
}
public void fileTransfer() {
ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
for (int i=0; i < 4; i++) {
pool.submit(new CopyThread());
}
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class CopyThread implements Runnable {
private static int counter = 0;
public void report(String bitrate) {
System.out.println(bitrate);
}
Object obj = new Object();
@Override
public void run() {
synchronized(obj) {
System.out.println("This is the " + (++counter) + " thread");
long startTime = System.nanoTime();
long bytes = 0;
for(int i=0; i<100000; i++)
bytes+=1;
long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / 1000000000; // get in seconds
double bytesInMegas = (double) bytes / 1000000;
report(bytesInMegas + "MB were transferred in " + duration + " seconds");
}
}
}
public class Cat {
public static void main(String[] args) {
Copier copier = Copier.getInstance();
copier.fileTransfer();
}
}