Java 原子整数是如何工作的?

Java 原子整数是如何工作的?,java,Java,我没想到穿线会这么困难。 无论如何,我能想到的在线程完成后执行函数的唯一方法是在线程运行时使用静态计数器递增 if(++threadcounter==3){doSomething(); threadcounter =0;} 我发现这不是一个好主意,因为线程计数器有时从未达到4 所以我用了原子整数 if(atomicint.incrementAndGet()==4){doSomething(); atomicint.set(0);} 计数器为5或0,应用程序冻结。我不知道发生了什么事。如何使用

我没想到穿线会这么困难。 无论如何,我能想到的在线程完成后执行函数的唯一方法是在线程运行时使用静态计数器递增

if(++threadcounter==3){doSomething(); threadcounter =0;}
我发现这不是一个好主意,因为线程计数器有时从未达到4

所以我用了原子整数

if(atomicint.incrementAndGet()==4){doSomething(); atomicint.set(0);}
计数器为5或0,应用程序冻结。我不知道发生了什么事。如何使用正确的计数器? 谢谢


编辑:

您使用的是哪种线程?假设采用一种简单的方法(只需旋转),您可以在函数脱离循环后立即调用它


也许如果您发布了更多的代码?

不要使用AtomicInteger,它与您想要做的并不匹配。使用Thread.join等待线程终止。

这不是问题的适用解决方案检查注释

您可以使用来完成线程,或者如果您需要一些计数器,我建议使用类似的易失性原语

volatile int threadCount=0;
这将保证排序和立即写入内存。检查关键字的解释


希望这有助于

听起来像是在另一个线程中执行某个任务,可能会生成一个值,然后在初始线程中使用生成的值

可调用的
接口可能就是您想要的

final Callable<Integer> task = new Callable<Integer>() {
    @Override public Integer call() {
        // do computation
        return <some-integer>;
    }
};
Future<Integer> future = Executors.newSingleThreadExecutor().submit(task);

// you can do other stuff here, in your thread. the task will be executing

Integer result = future.get();
final Callable task=new Callable(){
@重写公共整数调用(){
//计算
返回;
}
};
Future Future=Executors.newSingleThreadExecutor().submit(任务);
//你可以在这里做其他事情,在你的线程中。任务将被执行
整数结果=future.get();

Future#get
将阻塞,直到线程完成。

更好的代码是

if(atomicint.incrementAndGet()%5==0){doSomething();} 
只要它不会超过你罚款的20亿倍

否则,您可以添加一个

int value;
if((value=atomicint.get())>=5)atomicint.compareAndSet(value,value%5);
但这并不理想,因为compareandset可能会无声地失败

或者,您可以创建自己的incrementModAndGet

public static int incrementModAndGet(AtomicInteger atomicint, int mod){
    int old,newval;
    do{
        old = atomicint.get();
        newval = (old+1)%mod;
    }while(!atomicint.compareAndSet(old,newval));
    return newval;
}

解决这一问题的最简单方法是使用一个好的老式锁:

boolean shouldDoSomething;
synchronized {
    ++threadCounter;
    if (threadCounter == 4) {
        threadCounter = 0;
        shouldDoSomething = true;
    }
    else {
        shouldDoSomething = false;
    }
}
if (shouldDoSomething) doSomething();
这将在锁上产生争用,但争用的代码非常、非常简短——加载、存储和一些算术指令


您使用的
AtomicInteger
是错误的,因为没有锁或其他并发控制将
incrementAndGet
set
链接起来,这意味着存在潜在的竞争条件(值为3,线程a增加到4,线程B增加到5,线程a设置到0)。

您的意思是什么?我只是用普通的线。带有计时器的进度条。然后将变量增加1。但这不正确,我想我和塔索斯在这件事上是一致的,它冻结了进度条。不是一个好的解决方案。我还没有弄清楚如何使用itAh,你没有提到-如果你有一个swing UI,就用SwingUtilities.runLater在UI线程中运行一些东西。我想我已经修复了它。我使用了一个synchronize(MyClass.this),然后在同步的块中增加。它似乎可以工作,但我不确定同步的作用。它是否确保一个线程必须等待另一个线程完成该块的使用,然后该线程才能使用该代码块?我的意思是,所有线程最终都会访问同步块吗?我假设可以使用它。谢谢我将使它成为一个普通的int,并使用syncrhonized来增加计数器。感谢-1:volatile的使用并不能提供OP所需的保证。Volatile提供了可见性保证,但它无法阻止两个线程之间的竞争。哦,是的,我明白了:“只有在一组受限制的情况下,才能使用可变变量而不是锁。volatile变量必须满足以下两个标准才能提供所需的线程安全性:1。对变量的写入不取决于其当前值。2.该变量不参与其他变量的不变量。“来自ibm开发人员。潜在的竞争是A读X,B读X,A写X+1,B写X+1。波动性将确保读操作看到以前任何写入操作的结果,并且写入操作对任何后续读取都是可见的,但它不会阻止竞争。要记住的是,尽管++是一个单独的操作符,但它实际上涉及两个完全独立的内存操作!顺便说一下,我在run方法中有synchronized块。这是个好主意吗?其他答案都很好,但这是最简单的。顺便说一句,问题仍然存在,在@Override run方法中进行同步是一个好主意吗:)您应该使同步块尽可能小,以便线程不会不必要地相互阻塞。这通常意味着在方法中使用同步块,而不是同步方法?您是为所有线程使用
Runnable
类的单个实例,还是它们有自己的实例?每个线程都有相同的运行方法。run方法有一个同步块来增加静态变量。很好!第二个版本看起来应该这样做;只要在
值%5
而不是
的基础上做出
doSomething()
的决定,并且只要在达到20亿之前降低该值的一次尝试成功,则无提示故障是良性的。这看起来也非常有效:我认为处理器在执行代码时所采取的操作基本上相当于一次
递增和获取
,或者获取(但不释放)锁。我有一个类似的用例,尝试将AsyncTasks转换为ExecutorService,以从文件室数据库返回列表。另一个答案建议在ExecutorService上使用submit(),在Dao方法上使用get()(请参阅stackoverflow.com/questions/52242933/room database query)。感谢您对该方法的想法,而不是您使用电话的方法