为什么这些线程 运行 不按顺序排列?

Why don't these threads run in sequence?

我很难理解synchronized和可重入锁。这是我正在试验的小程序:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Reentr {

    public static void main(String[] args) {
        ExecutorService eService = Executors.newFixedThreadPool(2);
        for (int i = 1; i <= 2; i++) {
            eService.execute(new process());
        }

        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        eService.shutdown();
    }

}

class process implements Runnable {
    int count = 0;

    @Override
    public void run() {

        processTest();
    }

    public synchronized void processTest() {
        try {
            for (int i = 1; i <= 2; i++) {
                count += i;
                System.out.println("count value for " + Thread.currentThread().getName() + " is " + count);
            }
        } finally {
            System.out.println("count for " + Thread.currentThread().getName() + " is " + count);
        }
    }

}

输出为:

count value for pool-1-thread-2 is 1
count value for pool-1-thread-1 is 1
count value for pool-1-thread-2 is 3
count for pool-1-thread-2 is 3
count value for pool-1-thread-1 is 3
count for pool-1-thread-1 is 3

如果我们在输出中看到两个线程在同步块中。我的印象是一个线程必须完成synchronized方法的执行,之后另一个线程才会进入该方法。

理想情况下,我期待这样的结果

count value for pool-1-thread-1 is 1
count value for pool-1-thread-1 is 3
count for pool-1-thread-1 is 3
count value for pool-1-thread-2 is 1
count value for pool-1-thread-2 is 3
count for pool-1-thread-2 is 3

我已经用同步块和可重入锁替换了同步方法。但是,我仍然有相同的输出。我错过了什么?

当实例方法被声明时synchronized,它在对象实例上同步。由于你在每次循环迭代中都是运行一个new process(),对象实例不一样,所以同步是没有意义的。尝试创建一个 process 对象并将其传递给您启动的两个线程。

执行此操作时,还要将 count 实例变量移动到 processTest 方法中。这样它将是线程安全的。

两个线程没有在同一个对象上同步。

您有两个不同的 process 实例(顺便说一句;您应该始终使用大写字母命名 类)。 synchronized 关键字等同于:

public void processTest() {
  synchronized(this) {
    // etc..
  }
}

如果您希望一个线程在另一个线程之后 运行,它们必须在同一个对象上同步。如果您这样做,例如:

class process implements Runnable {
  // note that this is static
  private static final Object lock = new Object();

  public void processTest() {
    synchronized(lock) {
      // your code
    }
  }
}

那么您的代码将有一个线程 运行 接一个线程。另一种方法是将锁传递给 Objects 构造函数,或 Semaphore 的相同实例,等等