在Java多线程中使用synchronized关键字时未获得预期结果。

huangapple go评论73阅读模式
英文:

Not getting desired result when using synchronized keyword in Java multithreading

问题

以下是您提供的内容的翻译部分:

我有两个文件,App.javaRunner.java

App.java -->

public class App {
    private static Thread thread1 = new Runner(1);
    private static Thread thread2 = new Runner(2);

    public static void main(String[] args) throws InterruptedException {
        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.printf("Count = %d\n", Runner.getCount());
    }
}

Runner.java -->

public class Runner extends Thread {
    private volatile static int count = 0;
    private int option = 0;

    private synchronized void increment() {
        count++;
    }

    private synchronized void decrement() {
        count--;
    }

    public Runner(int option) {
        this.option = option;
    }

    public static int getCount() {
        return count;
    }

    @Override
    public void run() {
        switch (option) {
            case 1:
                for (int i = 1; i <= 10000; i++) {
                    increment();
                }
                break;
            case 2:
                for (int i = 1; i <= 10000; i++) {
                    decrement();
                }
                break;
        }
    }
}

在这里,我试图从 main 线程创建两个 threads,并从这两个线程中访问一个共同的变量,这两个线程将同时操作这个共同的变量。

我试图创建一个演示用的实现 synchronized 关键字的示例。

在我的示例中,在 Runner.java 中 -

我将 Runner 类通过 extends 关键字作为 Thread 类的子类,同时在其主体中覆盖了 run() 方法。

接下来,我使用一个构造函数来获取一个 option,并在 run() 方法中运行相应的代码,使用 switch - case 语句块。共同的变量是 count,它是一个初始值为 0 的静态变量。

有两个方法,都使用了 synchronized 关键字 - increment()decrement(),分别将 count 的值增加和减少 1。

对于 option 1run() 方法使用一个循环来运行 increment() 10,000 次。
对于 option 2run() 方法使用一个循环来运行 decrement() 10,000 次。

因此,count 的最终值应该为 0。

App.java 中 -

我创建了两个线程 - thread1thread2,它们都是 Runner class 的实例,并分别传递了构造函数参数 1 和 2。

我使用 thread.start() 运行这两个线程,并使用 thread.join() 等待这两个线程的完成。

现在,我打印了 count 的值。预期值应该是 0。但实际上不是。在每次执行中,它都接近于 0,但不是 0。

因此,我在哪里出错了,如何纠正我的代码?

英文:

I have two files, App.java and Runner.java

App.java -->

public class App {
    private static Thread thread1 = new Runner(1);
    private static Thread thread2 = new Runner(2);

    public static void main(String[] args) throws InterruptedException {
        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.printf("Count = %d\n", Runner.getCount());
    }
}

Runner.java -->

public class Runner extends Thread {
    private volatile static int count = 0;
    private int option = 0;

    private synchronized void increment() {
        count++;
    }

    private synchronized void decrement() {
        count--;
    }

    public Runner(int option) {
        this.option = option;
    }

    public static int getCount() {
        return count;
    }

    @Override
    public void run() {
        switch (option) {
            case 1:
                for (int i = 1; i <= 10000; i++) {
                    increment();
                }
                break;
            case 2:
                for (int i = 1; i <= 10000; i++) {
                    decrement();
                }
                break;
        }
    }
}

Here I am trying to create two threads from main thread and access a common variable from both the threads where both the threads will manipulate this common variable at the same time.

I am trying to create a demo for implementation for the synchronized keyword.

In my example, in Runner.java -

I am making Runner class a child class of Thread using extends keyword and overriding the run() method in body.

Next, I am using a constructor to get an option and running the respective code in run() method in a switch - case block. The common variable is count which is static with initial value 0.

There are two methods, both use the synchronized keyword - increment() and decrement() which increase and decrease the value of count by 1 respectively.

For option 1 run() method uses a for loop to run increment() 10,000 times.
For option 2 run() method uses a for loop to run decrement() 10,000 times.

As such the end value of count should be 0.

In App.java -

I am creating two threads - thread1, thread2 which are instances of Runner class and passing constructor argument 1 and 2 respectively.

I am running the two threads using thread.start() and waiting for completion of the two threads using thread.join()

Now, I am printing the value of count. The value is expected to be 0. But it is not. In each execution it is near to 0 but not 0.

So, where am I going wrong and how to correct my code?

答案1

得分: 1

count 是静态的,意味着只有一个这样的变量。
incrementdecrement 都不是静态的,这意味着它们在 this 上是同步的 - 即两个独立的 Runner 实例。

将这些方法改为静态的:

private static void increment() {
    synchronized (Runner.class) {
        count++;
    }
}

private static void decrement() {
    synchronized (Runner.class) {
        count--;
    }
}

或者使用显式的互斥对象:

private static int count = 0;
private static Object mutex = new Object();

private int option = 0;

private void increment() {
    synchronized (mutex) {
        count++;
    }
}

private void decrement() {
    synchronized (mutex) {
        count--;
    }
}
英文:

count is static meaning there is only one such variable.
Both increment and decrement are not static which means they are synchronized on this - that is two separate Runner instances.

Make those method static:

private synchronized static void increment() {
    count++;
}

private synchronized static void decrement() {
    count--;
}

or use explicit mutex object:

private static int count = 0;
private static Object mutex = new Object;

private int option = 0;

private void increment() {
    synchronized (mutex) {
        count++;
    }
}

private void decrement() {
    synchronized (mutex) {
        count--;
    }
}

huangapple
  • 本文由 发表于 2020年9月10日 05:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/63819807.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定