如何确定方法必须同步

时间:2013-02-17 07:02:46

标签: java multithreading

在从this test thread code获取的代码中,一个线程调用两个方法addToTotal()countPrimes(),但只有前者被标记为synchronized。

正在执行countPrimes()时阻止交错的原因。 {i},min,max,count等countPrimes()使用的变量也不是共享资源。那个由isPrime()调用的countPrimes()呢?

   public class ThreadTest2 {

    private static final int START = 3000000;

    private static int total;

    synchronized private static void addToTotal(int x) {
        total = total + x;
        System.out.println(total + " primes found so far.");
    }

    private static class CountPrimesThread extends Thread {
        int count = 0;
        int min, max;
        public CountPrimesThread(int min, int max) {
            this.min = min;
            this.max = max;
        }
        public void run() {
            count = countPrimes(min,max);
            System.out.println("There are " + count + 
                " primes between " + min + " and " + max);
            addToTotal(count);
        }
    }

    private static void countPrimesWithThreads(int numberOfThreads) {
        int increment = START/numberOfThreads;
        System.out.println("\nCounting primes between " + (START+1) + " and " 
            + (2*START) + " using " + numberOfThreads + " threads...\n");
        long startTime = System.currentTimeMillis();
        CountPrimesThread[] worker = new CountPrimesThread[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++)
            worker[i] = new CountPrimesThread(START+i*increment+1, START+(i+1)*increment );
        total = 0;
        for (int i = 0; i < numberOfThreads; i++)
            worker[i].start();
        for (int i = 0; i < numberOfThreads; i++) {
            while (worker[i].isAlive()) {
                try {
                    worker[i].join();
                } catch (InterruptedException e) {
                }
            }
        }
        long elapsedTime = System.currentTimeMillis() - startTime;
        System.out.println("\nThe number of primes is " + total + ".");
        System.out.println("\nTotal elapsed time:  " + (elapsedTime/1000.0) + " seconds.\n");
    }

    public static void main(String[] args) {
        int processors = Runtime.getRuntime().availableProcessors();
        if (processors == 1)
            System.out.println("Your computer has only 1 available processor.\n");
        else
            System.out.println("Your computer has " + processors + " available processors.\n");
        int numberOfThreads = 0;
        while (numberOfThreads < 1 || numberOfThreads > 5) {
            System.out.print("How many threads do you want to use  (from 1 to 5) ?  ");
            numberOfThreads = TextIO.getlnInt();
            if (numberOfThreads < 1 || numberOfThreads > 5)
                System.out.println("Please enter 1, 2, 3, 4, or 5 !");
        }
        countPrimesWithThreads(numberOfThreads);
    }

    private static int countPrimes(int min, int max) {
        int count = 0;
        for (int i = min; i <= max; i++)
            if (isPrime(i))
                count++;
        return count;
    }

    private static boolean isPrime(int x) {
        int top = (int)Math.sqrt(x);
        for (int i = 2; i <= top; i++)
            if ( x % i == 0 )
                return false;
        return true;
    }
}

3 个答案:

答案 0 :(得分:5)

countPrimes不需要同步,因为它不访问任何共享变量(它只适用于参数和局部变量)。所以没有什么可以同步的。

另一方面,total变量从多个线程更新,并且需要同步访问以确保正确性。

答案 1 :(得分:3)

  

当执行countPrimes()时,什么阻止交错?

无。我们不需要阻止它(见下文)。而且由于我们不需要,防止交错会是一件坏事,因为它会降低并行性。

  

countPrimes()imin count`等max,使用的变量不是共享资源吗?

没有。它们是当前线程的本地;即,run()方法调用正在进行的线程。没有其他人分享他们。

  

isPrime()调用的countPrimes()呢?

同样的交易。它只使用局部变量,因此不需要同步。

答案 2 :(得分:0)

synchronized关键字只是获取某个对象的监视器。如果另一个线程已经有了监视器,它必须等待该线程完成才能获取它并继续。在公共对象上同步的任何代码都将无法并发运行,因为在任何给定时间只有一个线程可以获取该对象上的监视器。在方法的情况下,监视器使用是隐含的。对于非静态方法,它是被调用的实例,对于静态方法,它是调用它的类型的类。

这是一个可能的原因,但它几乎不能准确表明何时使用关键字。

要回答这个问题,我会说你在不希望两个线程同时执行基于公共监视器的关键部分时使用synchronized。您需要这种情况的情况很多,并且充斥着过多的陷阱和例外以便完全解释。

您不能阻止使用synchronized访问整个类。你可以使每个方法同步,但这仍然不是一回事。另外,它只会阻止其他线程在同一台监视器上同步时访问关键部分。