Java 以下级别的螺纹安全装置是否会断裂;我相信它可以';我不想,只是想加倍肯定,因为这不容易测试 公共类ThreadSafe实现ITaskCompletionListener{ 私有最终集taskIds=newhashset(); private final Set successfulIds=new HashSet(); private final Set canceledids=new HashSet(); private final Set errorIds=new HashSet(); 公共线程安全(){ } //同时调用 @凌驾 取消后的公共无效(字符串){ 拆除(PTA撬块); 已取消的ID。添加(PTA撬块); } //同时调用 @凌驾 公共空隙收集器(管柱){ 拆除(PTA撬块); errorIds.add(PTA滑轨); } //同时调用 @凌驾 成功时的公共无效(字符串){ 拆除(PTA撬块); successfulIds.add(pTaskId); } 专用空隙移除(管柱撬块){ 拆除(PTA撬块); } }

Java 以下级别的螺纹安全装置是否会断裂;我相信它可以';我不想,只是想加倍肯定,因为这不容易测试 公共类ThreadSafe实现ITaskCompletionListener{ 私有最终集taskIds=newhashset(); private final Set successfulIds=new HashSet(); private final Set canceledids=new HashSet(); private final Set errorIds=new HashSet(); 公共线程安全(){ } //同时调用 @凌驾 取消后的公共无效(字符串){ 拆除(PTA撬块); 已取消的ID。添加(PTA撬块); } //同时调用 @凌驾 公共空隙收集器(管柱){ 拆除(PTA撬块); errorIds.add(PTA滑轨); } //同时调用 @凌驾 成功时的公共无效(字符串){ 拆除(PTA撬块); successfulIds.add(pTaskId); } 专用空隙移除(管柱撬块){ 拆除(PTA撬块); } },java,multithreading,concurrency,hashset,Java,Multithreading,Concurrency,Hashset,来自文档: 请注意,此实现未同步。如果多个线程同时访问哈希集,并且至少有一个线程修改了该集,则必须在外部对其进行同步 因此,您的代码不是线程安全的。对任何方法的并发访问都可能会产生奇怪的结果。方法onError、onSuccess和onCancel可以由两个或多个线程并行调用,这可能最终调用taskIds。并行删除,这是线程安全的 只要将这三种方法标记为synchronized,您就应该这样做。我认为您应该在并发调用的方法中使用同步块 范例 public class ThreadSafe imp

来自文档:

请注意,此实现未同步。如果多个线程同时访问哈希集,并且至少有一个线程修改了该集,则必须在外部对其进行同步


因此,您的代码不是线程安全的。对任何方法的并发访问都可能会产生奇怪的结果。

方法
onError
onSuccess
onCancel
可以由两个或多个线程并行调用,这可能最终调用
taskIds。并行删除
,这是线程安全的


只要将这三种方法标记为
synchronized
,您就应该这样做。

我认为您应该在并发调用的方法中使用同步块

范例

public class ThreadSafe implements ITaskCompletionListener {

private final Set<String> taskIds = new HashSet<String>();
private final Set<String> successfulIds = new HashSet<String>();
private final Set<String> cancelledIds = new HashSet<String>();
private final Set<String> errorIds = new HashSet<String>();

public ThreadSafe() {

}

// invoked concurrently
@Override
public void onCancel(String pTaskId) {
    remove(pTaskId);
    cancelledIds.add(pTaskId);
}

// invoked concurrently
@Override
public void onError(String pTaskId) {
    remove(pTaskId);
    errorIds.add(pTaskId);
}

// invoked concurrently
@Override
public void onSuccess(String pTaskId) {
    remove(pTaskId);
    successfulIds.add(pTaskId);
}

private void remove(String pTaskId) {
    taskIds.remove(pTaskId);
}

}

您可以使用线程安全的单个集合,而不是在集合之间拥有大量集合和传递ID

public void onCancel(String pTaskId) {
synchronized(this){
    remove(pTaskId);
    cancelledIds.add(pTaskId);
}
}
private final ConcurrentMap idState=new ConcurrentHashMap();
枚举状态{任务,成功,取消,错误}
成功时公共无效(字符串taskId){
idState.put(taskId,State.SUCCESS);
}
已取消的公共void(字符串taskId){
idState.put(taskId,State.CANCELLED);
}
public void onError(字符串taskId){
idState.put(taskId,State.ERROR);
}
删除公共void(字符串taskId){
idState.remove(任务ID);
}
彼得是对的。 您可以使用线程安全的单个集合,而不是在集合之间拥有大量集合和传递ID


这将使它变得不那么复杂,并且看起来不容易被破坏。

此代码充满了线程安全问题

HashSet不是线程安全的(它基于非线程安全的HashMap-race条件,在这种情况下可能导致错误)

其次,在
taskIds
集中的ID和它被添加到其他ID集中的ID之间没有原子性,因此任务的存在是短暂的


第三,代码隐式地假设任务状态只是inProgress->success | error | cancel,并且没有并发任务执行。如果这不是真的,那么代码将失败。

感谢你们每个人的响应,也感谢你们指出我粘贴的代码中明显的错误。我将给出我正在解决的问题的背景

我将接收请求(每个请求将有一组任务id);我有一个线程池,用于提交此请求(每个请求的一批任务)。我将接受任务完成后将调用的客户端侦听器。在当前上下文中,我可以使用
ExecutorCompletionService
等待与请求相对应的所有任务完成,但是,我不希望进行任何阻塞调用

相反,我希望子类化
FutureTask
(覆盖
done()
方法),这将在我的子类executor服务的
newTaskFor()
中实例化。与一个请求相对应的所有未来任务将共享
TaskCompletionListener
,并且在override
done()
方法中将调用
success()
error()
或cancel中的一个。
TaskCompletionListener
将使用任务id(任务数)的初始集进行初始化,对于每次调用,计数将减少1,之后将发出完成信号

这里是代码的修改版本,我希望这次我没有犯太多错误(是的,再次感谢上次所有的答案)

公共类TaskCompletionListener实现ITaskCompletionListener{
私有最终原子整数任务计数;
私有最终IProcessCompletionListener completionListener;
公共任务CompletionListener(最终哈希集pTaskIds、IProcessCompletionListener pCompletionListener){
taskCount=新的AtomicInteger(pTaskIds.size());
completionListener=pCompletionListener;
}
//同时调用
@凌驾
取消后的公共无效(字符串){
检查完成();
}
//同时调用
@凌驾
公共空隙收集器(管柱){
检查完成();
}
//同时调用
@凌驾
成功时的公共无效(字符串){
检查完成();
}
私有无效检查完成(){
//方法级限制
int currentCount=taskCount.decrementAndGet();
如果(currentCount==0){
completionListener.onProcessComplete();
}
}
接口IProcessCompletionListener{
void onProcessComplete();
}
}

Or--像这样更改每个字段的初始值设定项:private final Set taskIds=Collections.synchronizedSet(new HashSet());实际上,使单个集合同步将使代码在技术上是线程安全的,但在概念上可能不是线程安全的,因为集合之间的移动在概念上可能是原子的。这一点很好!因此,请使用公共方法上的同步:)嗨@Jennah,欢迎使用So!我只是想告诉你,一般来说,在你的帖子上加个人签名被认为是不礼貌的。因此将自动为y添加签名
private final ConcurrentMap<String, State> idState = new ConcurrentHashMap<String, State>();
enum State { TASK, SUCCESS, CANCELLED, ERROR }

public void onSuccess(String taskId) {
    idState.put(taskId, State.SUCCESS);
}

public void onCancelled(String taskId) {
    idState.put(taskId, State.CANCELLED);
}

public void onError(String taskId) {
    idState.put(taskId, State.ERROR);
}

public void remove(String taskId) {
    idState.remove(taskId);
}
public class TaskCompletionListener implements ITaskCompletionListener {

private final AtomicInteger taskCount;

private final IProcessCompletionListener completionListener;

public TaskCompletionListener(final HashSet<String> pTaskIds, IProcessCompletionListener pCompletionListener) {
    taskCount = new AtomicInteger(pTaskIds.size());
    completionListener = pCompletionListener;
}

// invoked concurrently
@Override
public void onCancel(String pTaskId) {
    checkCompletion();
}

// invoked concurrently
@Override
public void onError(String pTaskId) {
    checkCompletion();
}

// invoked concurrently
@Override
public void onSuccess(String pTaskId) {
    checkCompletion();
}

private void checkCompletion() {
              // method level confinement  
    int currentCount = taskCount.decrementAndGet();
    if (currentCount == 0) {
        completionListener.onProcessComplete();
    }
}

interface IProcessCompletionListener {
    void onProcessComplete();
}
}