通过'100个不同的线程递增静态变量而不同步,但最终结果为100

时间:2014-07-04 01:51:06

标签: java multithreading synchronized

我通过增加一个静态变量来实现。 100个不同的线程没有同步,但最终结果为100.我已经多次运行此代码并得到相同的结果。我的代码不需要同步吗?我使用BlueJ IDE来运行代码

    public class Main {
        private final static int MAX_THREADS = 100;
        public static void main(String[] args) {
            Thread[] threads = new Thread[MAX_THREADS];

            for(int i=0; i<MAX_THREADS; i++) {
                threads[i] = new Thread(new Job(), "Thread-" + i);
                threads[i].start();
                try{
                    Thread.sleep((int)(Math.random() * 1000));
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }

            for(int i=0; i<MAX_THREADS; i++) {
                try {
                    threads[i].join();
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.printf("Final Value: %d\n", Job.getSuccessCount());
        }

    }

    public class Job implements Runnable {
        private  static int successCount;

        public  static int getSuccessCount() {return successCount;}

        @Override
        public void run() {
            System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
            try{
                Thread.sleep((int)(Math.random() * 10000));
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
            successCount++;
            System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
        }
    }

4 个答案:

答案 0 :(得分:2)

基本上在你的代码中,由于sleep语句(在线程和启动器中都有),你实际上开始了线程,允许大量的非繁忙时间进行更新。这就是它工作的原因。如果您的代码实际上是多线程的,那么您将面临同步问题。

答案 1 :(得分:0)

添加Wombat的答案。最终结果将始终为100,因为您在Job课程中进行睡眠后进行一元操作。基本上,如果Java Scheduler在执行以下操作时没有更改线程的状态,则每个Job可以按顺序运行read-modify-write命令。

successCount++

但是,如果您将Job源代码更改为read-sleep-modify-write,那么您肯定会看到过时的陈旧值。

public class Job implements Runnable {
    private  static int successCount;

    public  static int getSuccessCount() {return successCount;}

    @Override
    public void run() {
        System.out.printf("%s: Incrementing successCount %d\n", Thread.currentThread().getName(), successCount);
        int sc = successCount; // Read
        try{
            Thread.sleep((int)(Math.random() * 10000)); // Sleep
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
        successCount = sc++; // Modify-Write
        System.out.printf("%s: Incrementing Complete %d\n", Thread.currentThread().getName(), successCount);
    }
}

使用这2个线程可以读取然后休眠,然后唤醒并写入相同的值到successCount覆盖原始值。

答案 2 :(得分:0)

您的代码目前不需要同步,因为没有两个代码同时访问同一个变量。换句话说,应用程序中只有一个线程正在递增变量。

在这种情况下,这是因为递增变量所需的数量少于Math.random()* 1000。为什么会这样?让我们观察线程:

主线程:

  1. 启动并启动一个主题
  2. 执行Math.random()和Thread.sleep()
  3. 再次循环
  4. 当主线程正在执行第2步时,新线程是:

    1. 增量变量
    2. 去睡觉
    3. 在这种情况下,一旦新线程进入休眠状态,它就会立即被杀死,因此,为了我们的目的,我们可以将其视为线程在步骤1之后立即终止,因为它会停止影响变量(它具有在步骤1)之后对变量没有影响。

      为了发生同步问题,两个新线程需要一次访问该变量。为此,主线程必须在第一个新线程完成递增之前启动一个新线程。为了实现这一点,主线程必须更快:执行Math.random(),Thread.sleep()和创建新线程,所有这些都在另一个线程完成递增之前。显然不是这种情况,因此没有2个线程会立即递增,并且不会发生同步错误。

答案 3 :(得分:0)

如果你做了总和,你会发现平均有10个线程在同一时间运行,所有线程平均睡眠时间为5秒,然后进行增量。因此,平均而言,增量不会比半秒更接近,并且它们的起点也平均间隔半秒这一事实使得平均值达到整秒。这里基本上没有并发性。