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

时间:2015-08-17 04:13:43

标签: java multithreading concurrency synchronized

我很难理解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块和可重入锁替换了synchronized方法。但是,我仍然有相同的输出。我错过了什么?

2 个答案:

答案 0 :(得分:1)

当声明实例方法synchronized时,它会在对象实例上同步。由于在每次循环迭代中运行new process(),因此对象实例不同,因此同步毫无意义。尝试创建一个process对象并将其传递给您开始的两个线程。

当您这样做时,也将count实例变量移动到processTest方法中。这样它就是线程安全的。

答案 1 :(得分:1)

两个线程不同步同一个对象。

您有两个不同的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
    }
  }
}

然后你的代码会有一个线程在另一个之后运行。另一种方法是将锁传递给Object构造函数,或Semaphore的相同实例等。