原子长整型在多线程中

huangapple go评论91阅读模式
英文:

AtomicLong in Multithreading

问题

public class Account implements Runnable {

    private final AtomicLong amount = new AtomicLong(0);

    public Account(long difference) {
        amount.set(difference);
    }

    public void run() {
        System.out.println("The Balance is : " + amount);
    }
}

public class Examples {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        IntStream.range(0, 100).forEach(i -> service.submit(new Account(i)));
    }
}

I tried to use Read/Write Lock and block level synchronization but no luck. Could please someone spot where am doing mistake?

I output has to be starts from 0,1,2...99.

英文:

I'm trying to use AtomicLong in Multi Threading Environment. My desired result is not working,

public class Account implements Runnable {

    private final AtomicLong amount = new AtomicLong(0);

    public Account(long difference) {
        amount.set(difference);
    }

    public void run() {
        System.out.println("The Balance is : " + amount);
    }
}
public class Examples {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        IntStream.range(0, 100).forEach(i -> service.submit(new Account(i)));
    }
}

I tried to use Read/Write Lock and block level synchronization but no luck. Could please someone spot where am doing mistake?

I output has to be starts from 0,1,2...99.

答案1

得分: 4

没有数据在任何线程之间共享...每个线程都创建自己的AtomicLong,没有共享。即使它被共享了,也不能保证数字会按顺序打印出来。甚至不能保证所有的数字都会被打印出来(有些数字可能会被打印多次)。

如果我将您的代码更改如下:

public static class Account implements Runnable {
    private static final AtomicLong amount = new AtomicLong(0);

    public Account(long difference) {
        amount.set(difference);
    }

    public void run() {
        System.out.println("The Balance is : " + amount);
    }
}

这是我得到的输出示例:

The Balance is : 2
The Balance is : 2
The Balance is : 2
The Balance is : 4
The Balance is : 5
The Balance is : 6
The Balance is : 7
The Balance is : 8
The Balance is : 9
The Balance is : 9

原因是以下情景是可能的:

  • 主线程创建Account(0)。这将0写入共享的AtomicLong
  • Thread-0启动
  • 主线程创建Account(1)。这将1写入共享的AtomicLong
  • Thread-0打印值,现在是1。在这种情况下,0永远不会被打印出来。

AtomicLong唯一保证的是对值的所有写入始终对所有在之后进行读取的线程可见。

原子变量的属性在Java文档中有详细说明(请参见这里)。

英文:

There's no data shared between any of your threads... each creates its own AtomicLong, no sharing. Even if it was shared there would be no guarantee at all that the numbers will print in order. They would not even be a guarantee that all numbers are printed (some of them could be printed more than once).

If I change your code like this:

public static class Account implements Runnable {
    private static final AtomicLong amount = new AtomicLong(0);

    public Account(long difference) {
        amount.set(difference);
    }

    public void run() {
        System.out.println("The Balance is : " + amount);
    }
}

Here's an example of output I get:

The Balance is : 2
The Balance is : 2
The Balance is : 2
The Balance is : 4
The Balance is : 5
The Balance is : 6
The Balance is : 7
The Balance is : 8
The Balance is : 9
The Balance is : 9

The reason is that the following scenario is possible:

  • main thread creates Account(0). This writes 0 to the shared AtomicLong.,
  • Thread-0 starts up
  • main thread creates Account(1). This writes 1 to the shared AtomicLong.
  • Thread-0 prints the value, it's now 1. In this case 0 will never be printed.

The only thing that AtomicLong does guarantee you is that all the writes to the value will always be visible by all threads making a read afterwards.

The properties of atomic variables are detailed in the javadoc (see here).

答案2

得分: 0

也许您的意思是这样的

public class Account implements Runnable {

    private final static AtomicLong seq = new AtomicLong(0);
    private final long amount;

    public Account() {
        amount = seq.getAndIncrement();
    }

    public void run() {
        System.out.println("余额为:" + amount);
    }
}

public class Examples {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        IntStream.range(0, 100).forEach(i -> service.submit(new Account()));
    }
}

这将确保每个账户都获得唯一的`amount`但这些值可能以不同的顺序打印出来
英文:

Maybe you meant something like that:

public class Account implements Runnable {

    private final static AtomicLong seq = new AtomicLong(0);
    private final long amount;

    public Account() {
        amount = seq.getAndIncrement();
    }

    public void run() {
        System.out.println("The Balance is : " + amount);
    }
}

public class Examples {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        IntStream.range(0, 100).forEach(i -> service.submit(new Account()));
    }
}

This will guarantee that each account will get a unique value of amount, but the values could be printed in different order.

huangapple
  • 本文由 发表于 2020年4月5日 01:44:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/61032236.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定