Java 如何确定方法必须同步

Java 如何确定方法必须同步,java,multithreading,Java,Multithreading,在这段代码中,来自线程的代码调用了两个方法addToTotal()和countPrimes(),但只有前者被标记为synchronized 当执行countPrimes()时,什么可以防止交织。countPrimes()使用的变量,如i、min、max、count,不也是共享资源吗。那么由countPrimes()调用的isPrime()呢 公共类ThreadTest2{ 专用静态最终整数起始=3000000; 私有静态整数合计; 同步私有静态void addtotal(int x){ 总计=总

在这段代码中,来自线程的代码调用了两个方法
addToTotal()
countPrimes()
,但只有前者被标记为synchronized

当执行
countPrimes()
时,什么可以防止交织。
countPrimes()
使用的变量,如i、min、max、count,不也是共享资源吗。那么由countPrimes()调用的
isPrime()

公共类ThreadTest2{
专用静态最终整数起始=3000000;
私有静态整数合计;
同步私有静态void addtotal(int x){
总计=总计+x;
System.out.println(总数+“到目前为止找到的素数”);
}
私有静态类CountPrimesThread扩展线程{
整数计数=0;
最小整数,最大整数;
public CountPrimesThread(int-min,int-max){
this.min=min;
this.max=max;
}
公开募捐{
计数=计数素数(最小值、最大值);
System.out.println(“有”+count+
“介于“+min+”和“+max”之间的素数);
加总(计数);
}
}
私有静态void countPrimesWithThreads(int numberOfThreads){
int增量=开始/线程数;
System.out.println(“\n计算“+(开始+1)+”和“之间的素数”
+(2*开始)+使用“+numberOfThreads+”线程…\n”);
long startTime=System.currentTimeMillis();
CountPrimesThread[]worker=新的CountPrimesThread[numberOfThreads];
for(int i=0;i5){
System.out.print(“要使用多少线程(从1到5)”;
numberOfThreads=TextIO.getlnInt();
如果(numberOfThreads<1 | | numberOfThreads>5)
System.out.println(“请输入1、2、3、4或5!”);
}
countPrimesWithThreads(线程数);
}
私有静态int countPrimes(int最小值,int最大值){
整数计数=0;

for(int i=min;i
countPrimes
不需要同步,因为它不访问任何共享变量(它只与参数和局部变量一起工作)。因此不需要同步


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

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

这是一个可能的原因,但它很难准确指示何时使用关键字

为了回答这个问题,我建议您在不希望两个线程同时执行基于公共监视器的关键部分时使用synchronized。您需要使用synchronized的情况有很多,并且有太多的gotcha和异常无法完全解释

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

在执行countPrimes()时,什么可以防止交错

没什么。我们不需要阻止它(见下文)。既然我们不需要,阻止交错将是一件坏事,因为它会降低并行性

countPrimes()
i
min
max,
count`这样的变量不也是共享资源吗

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

那么由countPrimes()调用的
isPrime()


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

OK。我认为这意味着局部变量和参数更新是自动同步的。@Himanshu它们不是同步的,它们是线程本地的(只有一个线程可以访问它们:运行该方法的线程).@Himanshu-如果某个东西只对一个线程可见,则不需要同步。局部变量和只对一个线程可见。下面是一些很好的答案。可以对代码进行注释。
addToTotal()
方法如果使用
   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;
    }
}