问题陈述: -
在我的下面的程序中,我使用的是ThreadPoolExecutor
ArrayBlockingQueue
。
每个线程每次都需要使用UNIQUE ID
,并且必须运行60 minutes or more
,所以60 minutes
所有ID's will get finished
都可能需要再次重用这些ID。所以我在这里使用ArrayBlockingQueue
概念。
两种情景: -
command.getDataCriteria()
包含Previous
,则每个
线程始终需要使用UNIQUE ID between 1 and 1000
和
释放它再次重复使用。command.getDataCriteria()
包含New
,则每个
线程始终需要使用UNIQUE ID between 2000 and 3000
和
释放它再次重复使用。我目前使用以下程序遇到了什么问题 -
我面临的一个问题是
run method
为command.getDataCriteria()
,则Previous
中的else if block(which is for New)
也会输入.equals check
,这不应该发生吗?而且我正在做else if(command.getDataCriteria().equals("New")) {
?为什么会这样?可能是因为许多线程会同时启动并在之前修改过命令? run method
如果多线程正在修改它,那么我如何克服这个问题呢?无论发生什么问题,都会发生在Synchronize the threads, so that no other thread should modify the command when another thread is trying to execute it.
。任何建议都会有很大的帮助,因为我长期坚持这一点。我们可能需要public synchronized void runNextCommand() {
LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();
LinkedList<Integer> availableNewIds = new LinkedList<Integer>();
executorService = new ThreadPoolExecutor(noOfThreads, noOfThreads, 500L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(noOfThreads), new ThreadPoolExecutor.CallerRunsPolicy());
// If there are any free threads in the thread pool
if (!(((ThreadPoolExecutor) executorService).getActiveCount() < noOfThreads))
return;
for (int i = 1; i <= 1000; i++) {
availableExistingIds.add(i);
}
for (int n = 2000; n <= 3000; n++) {
availableNewIds.add(n);
}
BlockingQueue<Integer> existIdPool = new ArrayBlockingQueue<Integer>(1000, false, availableExistingIds);
BlockingQueue<Integer> newIdPool = new ArrayBlockingQueue<Integer>(1001, false, availableNewIds);
// Running for particular duration of time
while(System.currentTimeMillis() <= endTime) {
Command nextCommand = getNextCommandToExecute();
Task nextCommandExecutorRunnable = new Task(nextCommand, existIdPool, newIdPool);
executorService.submit(nextCommandExecutorRunnable);
}
executorService.shutdown();
if (!executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS)) {
executorService.shutdownNow();
}
}
private static final class Task implements Runnable {
private Command command;
private DPSclient m_DPSclient = null;
private DPSclient psc = null;
private BlockingQueue<Integer> existPool;
private BlockingQueue<Integer> newPool;
private int existId;
private int newId;
private static Object syncObject = new Object();
public Task(Command command, BlockingQueue<Integer> pool1, BlockingQueue<Integer> pool2) {
this.command = command;
this.existPool = pool1;
this.newPool = pool2;
}
public void run() {
synchronized(syncObject) {
if(command.getDataCriteria().equals("Previous")) {
try {
// Getting existing id from the existPool
existId = existPool.take();
attributeGetSetMethod(existId);
} catch (Exception e) {
getLogger().log(LogLevel.ERROR, e.getLocalizedMessage());
} finally {
// And releasing that existing ID for re-use
existPool.offer(existId);
}
} else if(command.getDataCriteria().equals("New")) {
try {
// Getting new id from the newPool
newId = newPool.take();
attributeGetSetMethod(newId);
} catch (Exception e) {
getLogger().log(LogLevel.ERROR, e.getLocalizedMessage());
} finally {
// And releasing that new ID for re-use
newPool.offer(newId);
}
}
}
}
}
runnable(实际单元级命令执行器)的实现
getNextCommandToExecute method
我将非常感谢你对此的帮助。感谢
更新 - Matt建议的// Get the next command to execute based on percentages
private synchronized Command getNextCommandToExecute() {
int commandWithMaxNegativeOffset = 0; // To initiate, assume the first one has the max negative offset
if (totalExecuted != 0) {
// Manipulate that who has max negative offset from its desired execution
double executedPercentage = ((double)executedFrequency[commandWithMaxNegativeOffset] / (double)totalExecuted) * 100;
double offsetOfCommandWithMaxNegative = executedPercentage - commands.get(commandWithMaxNegativeOffset).getExecutionPercentage();
for (int j=1; j < commands.size(); j++) {
double executedPercentageOfCurrentCommand = ((double)executedFrequency[j] / (double)totalExecuted) * 100;
double offsetOfCurrentCommand = executedPercentageOfCurrentCommand - commands.get(j).getExecutionPercentage();
if (offsetOfCurrentCommand < offsetOfCommandWithMaxNegative) {
offsetOfCommandWithMaxNegative = offsetOfCurrentCommand;
commandWithMaxNegativeOffset = j;
}
}
}
// Next command to execute is the one with max negative offset
executedFrequency[commandWithMaxNegativeOffset] ++;
totalExecuted ++;
// This is for User Logging/No User Logging and Data is Previous/New
LinkedHashMap<String, Double> dataCriteriaMap = (LinkedHashMap<String, Double>) sortByValue(commands.get(commandWithMaxNegativeOffset).getDataUsageCriteria());
Set<Map.Entry<String, Double>> entriesData = dataCriteriaMap.entrySet();
Iterator<Map.Entry<String, Double>> itData = entriesData.iterator();
Map.Entry<String, Double> firstEntryData = itData.next();
Map.Entry<String, Double> secondEntryData = itData.next();
LinkedHashMap<Boolean, Double> userCriteriaMap = (LinkedHashMap<Boolean, Double>) sortByValue(commands.get(commandWithMaxNegativeOffset).getUserLoggingCriteria());
Set<Map.Entry<Boolean, Double>> entriesUser = userCriteriaMap.entrySet();
Iterator<Map.Entry<Boolean, Double>> itUser = entriesUser.iterator();
Map.Entry<Boolean, Double> firstEntryUser = itUser.next();
Map.Entry<Boolean, Double> secondEntryUser = itUser.next();
double percent = r.nextDouble() * 100;
if (percent < secondEntryData.getValue().doubleValue()) {
commands.get(commandWithMaxNegativeOffset).setDataCriteria(secondEntryData.getKey());
} else {
commands.get(commandWithMaxNegativeOffset).setDataCriteria(firstEntryData.getKey());
}
if (percent < secondEntryUser.getValue().doubleValue()) {
commands.get(commandWithMaxNegativeOffset).setUserLogging(secondEntryUser.getKey());
} else {
commands.get(commandWithMaxNegativeOffset).setUserLogging(firstEntryUser.getKey());
}
return commands.get(commandWithMaxNegativeOffset);
}
代码
private static List<Command> commands;
并且命令已在类的顶部声明为 -
private synchronized void attributeGetSetMethod(int id_range) {
requestlTransaction requestlTransaction = null;
try {
GUID_VALUES = new LinkedHashMap<Integer, String>();
// I am not sure how CAL logging has to be done, it has to be at each attribute level or something else? So that is the reason I left this thing.
if(!(command.getAttributeIDSet().isEmpty())) {
requestlTransaction = requestlTransactionFactory.create("DPSLnPTest");
m_DPSclient = setupDPS(command.getName(), getDPSAttributeKeys(command.getDataCriteria(), command.getUserLogging() , id_range));
for(String attr: command.getAttributeIDSet()) {
requestlTransaction.setName("DPSAttributeSet");
requestlTransaction.setStatus("0");
//requestlTransaction.addData("IpAddress", ipAddress);
if(attr.contains("/")) {
lengthOfString = Integer.parseInt(attr.split("/")[1]);
attr = attr.split("/")[0];
}
DPSAttribute attr1 = new DPSAttribute();
attr1.setRequestAttributeId(new DPSAttributeId(Integer.parseInt(attr)));
DPSMetadataMgr mgr = DPSMetadataMgr.getInstance();
DPSRequestAttributeMetadata metadata = mgr.getRequestAttributeMetadataById(Integer.parseInt(attr));
int maxOccurs = metadata.getMaxOccurs();
String dataType = metadata.getAttributeTypeAlias();
DPSAttributeValue attrValue1 = getRequestAttribute(dataType, lengthOfString);
if(maxOccurs>1) {
DPSListAttributeValue listAttrValue = new DPSListAttributeValue();
List<DPSAttributeValue> list = new ArrayList<DPSAttributeValue>();
list.add(attrValue1);
listAttrValue.setList(list);
attr1.setRequestAttributeValue(listAttrValue);
m_DPSclient.setDPSAttribute(attr1);
} else {
attr1.setRequestAttributeValue(attrValue1);
m_DPSclient.setDPSAttribute(attr1);
}
}
List<DPSAttribute> idKeys = m_DPSclient.release(PersistenceEnum.COMMIT, false);
// Iterating through the keys and storing into HashMap
Iterator<DPSAttribute> i = idKeys.iterator();
while (i.hasNext()) {
DPSAttribute DPSAttribute = (DPSAttribute)(i.next());
DPSAttributeId id = DPSAttribute.getAttributeId();
DPSAttributeValue value = DPSAttribute.getRequestAttribute();
if(id.getId() == DPSLnPConstants.CGUID_ID && (value)!= null) {
DPSLnPConstants.CGUID_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.CGUID_ID, DPSLnPConstants.CGUID_VALUE);
} else if(id.getId() == DPSLnPConstants.SGUID_ID && (value)!= null) {
DPSLnPConstants.SGUID_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.SGUID_ID, DPSLnPConstants.SGUID_VALUE);
} else if(id.getId() == DPSLnPConstants.PGUID_ID && (value)!= null) {
DPSLnPConstants.PGUID_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.PGUID_ID, DPSLnPConstants.PGUID_VALUE);
} else if(id.getId() == DPSLnPConstants.UID_ID && (value)!= null) {
DPSLnPConstants.UID_VALUE = String.valueOf(((DPSLongAttributeValue)value).getValue());
GUID_VALUES.put(DPSLnPConstants.UID_ID, DPSLnPConstants.UID_VALUE);
} else if(id.getId() == DPSLnPConstants.SITE_ID && (value)!= null) {
DPSLnPConstants.SITEID_VALUE = String.valueOf(((DPSIntAttributeValue)value).getValue());
GUID_VALUES.put(DPSLnPConstants.SITE_ID, DPSLnPConstants.SITEID_VALUE);
} else if(id.getId() == DPSLnPConstants.ALOC_ID && (value)!= null) {
DPSLnPConstants.ALOC_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.ALOC_ID, DPSLnPConstants.ALOC_VALUE);
} else if(id.getId() == DPSLnPConstants.ULOC_ID && (value)!= null) {
DPSLnPConstants.ULOC_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.ULOC_ID, DPSLnPConstants.ULOC_VALUE);
} else if(id.getId() == DPSLnPConstants.SLOC_ID && (value)!= null) {
DPSLnPConstants.SLOC_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.SLOC_ID, DPSLnPConstants.SLOC_VALUE);
} else if(id.getId() == DPSLnPConstants.PLOC_ID && (value)!= null) {
DPSLnPConstants.PLOC_VALUE = ((DPSStringAttributeValue)value).getValue();
GUID_VALUES.put(DPSLnPConstants.PLOC_ID, DPSLnPConstants.PLOC_VALUE);
}
}
// Storing all the locators, guid in a map corresponding to an ID, then later on insert everything directly into db
GUID_ID_MAPPING.put(id_range, GUID_VALUES);
// Sleeping the command for particular milliseconds
// One thing not sure, I should be sleeping the command here or I should put it above this comment line '// Iterating through the keys'
Thread.sleep(command.getSleepTime());
}
// for get attributes
// And also how CAL logging has to be done here too. And we can use same DPS Smart Client that got created above to get the attributes value?
if(!(command.getAttributeIDGet().isEmpty())) {
requestlTransaction.setName("DPSAttributeGet");
requestlTransaction.setStatus("1");
psc = setupDPS(command.getName(), getDPSAttributeKeys(command.getDataCriteria(), command.getUserLogging() , id_range));
for(String attr: command.getAttributeIDGet()) {
DPSAttribute attribute = new DPSAttribute();
attribute = psc.getDPSAttribute(new DPSAttributeId(Integer.parseInt(attr)));
//System.out.println(attribute.getAttributeId()+ " " +attribute.getRequestAttribute());
}
}
} catch(Exception e) {
getLogger().log(LogLevel.ERROR, e);
} finally {
requestlTransaction.completed();
}
}
更新一个方法: -
{{1}}
答案 0 :(得分:1)
从我所看到的command.getDataCriteria()
应该仅由一个Thread访问,那么它的'值不应该由于线程同步问题而改变。假设这样,我们希望确保没有两个线程获得对象实例的句柄。
您有synchronized getNextCommandToExecute()
但没有证据表明根据您的定义commands
同步了您的private static List<Command> commands;
收藏集。如果上面的假设是持有,我们要保证没有两个线程可以get()
来自Collection的同一个对象实例。
代码中的其他地方是从{
>访问的commands
集合
如果commands.get()
可以正确同步,那么返回的实例不应该有任何线程争用。哪个线程得到一个对象拥有它。
... 随时告诉我,我正在咆哮错误的树
[编辑] 关注您的评论
我很难确切地说出了什么问题,因为我没有所有的代码,而且还有一些假设。在我看来,您在许多方法上添加synchronized
关键字并希望它能够解决您的问题。我认为最好的方法是尽量减少真正需要同步的代码行,这需要更清楚地了解真正需要同步的内容。
您不希望跨线程共享对Command
对象的引用,因此请确保List<Command> commands
上的get()和add()操作已同步。您可以使用synchronizedList或ConcurrentLinkedQueue
可以使Command对象不可变吗? (即没有setX()方法)