Java并发:同步(Synchronized)不起作用

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

Java Concurrency Synchronized not working

问题

并发未按预期工作。

class Counter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException{
        Counter counter = new Counter();
        new Thread(() -> counter.increment()).start();
        new Thread(() -> counter.decrement()).start();
        System.out.println(counter.value());
    }
}

这段代码输出 1 而不是 0。我从 Oracle 的教程中复制了这个例子,不确定哪里出错了。

英文:

Concurrency is not working as expected.

class Counter {
	private int c = 0;

	public synchronized void increment() {
		c++;
	}

	public synchronized void decrement() {
		c--;
	}

	public synchronized int value() {
		return c;
	}
}


public class Main {
	public static void main(String[] args) throws InterruptedException{
		Counter counter = new Counter();
		new Thread(() -> counter.increment()).start();
		new Thread(() -> counter.decrement()).start();
		System.out.println(counter.value());
	}
}

This one prints 1 instead of 0. I copied this example from Oracle tutorial, I'm not sure where I'm wrong.

答案1

得分: 0

你没有等待线程完成。因此,你有可能出现这种情况:没有线程运行、两个线程都运行,或只有一个线程运行。因此,你的结果可能是 -1、0 或 1。你应该使用 join() 方法等待线程完成。

public void main(String[] args) throws InterruptedException{
    Counter counter = new Counter();
    Thread t1 = new Thread(() -> counter.increment());
    Thread t2 = new Thread(() -> counter.decrement());
    t1.start();
    t2.start();
    t1.join(); // 等待 t1 完成处理
    t2.join(); // 等待 t2 完成处理
    System.out.println(counter.value());
}

你还可以从 value() 方法中删除 synchronized,因为它不再在任何异步过程中使用。

英文:

You don't wait for your threads to finish. So you have the chance, that none, both or just one threads ran and so your result could be -1, 0 or 1. You should use join() to wait for your threads to finish.

public void main(String[] args) throws InterruptedException{
	Counter counter = new Counter();
	Thread t1 = new Thread(() -> counter.increment());
	Thread t2 = new Thread(() -> counter.decrement());
	t1.start();
	t2.start();
	t1.join(); // waits for t1 to end processing
	t2.join(); // waits for t2 to end processing
	System.out.println(counter.value());
}

You can also remove synchronized from value() because it is not used in any asynchronous process anymore.

答案2

得分: 0

在你的主函数中,执行线程与你的进程不是链接在一起的。Thread-2 可能会在 Thread-1 之前运行,它们都可能会在你的打印语句之后运行,反之亦然。尝试多次重新执行你的主函数,并打印出运行函数中的线程。这可以帮助你更好地理解。例如:

public static void main(String[] args) {
    Counter counter = new Counter();

    new Thread(() -> {
        counter.increment();
        System.out.println("Thread-1 increment");
    }).start();
    
    new Thread(() -> {
        counter.decrement();
        System.out.println("Thread-2 decrement");
    }).start();
    
    System.out.println(counter.value());
}
英文:

Execution thread in your main function are not linked to your process. Thread-2 could run before the Thread-1, they could both run after your print statement, and vice versa. Try to re-execute your main different times and print also the thread in run function. This can help you to understand better. For example:

public static void main(String[] args) {
Counter counter = new Counter();

    new Thread(() -> {
        counter.increment();
        System.out.println("Thread-1 increment");
    }).start();
    new Thread(() -> {
        counter.decrement();
        System.out.println("Thread-2 decrement");
    }).start();
    System.out.println(counter.value());
}

答案3

得分: 0

你需要在从线程获取结果之前在它们上使用join。
此外,你需要在每个将在异步线程中使用的方法上使用synchronized,例如这个示例中的increment和decrement方法。

我创建了一个示例来展示如果不在方法上添加synchronized会发生什么。

class Counter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public int value() {
        return c;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        for (int j = 0; j < 10; j++) {
            Counter counter = new Counter();
            List<Thread> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                list.add(new Thread(counter::increment));
                list.add(new Thread(counter::decrement));
            }

            for (Thread item : list) {
                item.start();
            }
            System.out.println("Results");
            System.out.println(counter.value());
            System.out.println(counter.value());
            System.out.println(counter.value());
            System.out.println(counter.value());
            System.out.println(counter.value());

            for (Thread item : list) {
                item.join();
            }

            System.out.println("Results after join");
            System.out.println(counter.value());
        }
    }
}

我运行了几次,有时即使使用了join,结果仍然是-3。

英文:

You need to use join on threads before getting results from them.
Also you need to use synchronize on each method which will be used in async Thread, in this example its increment and decrement method.

I made an example which shows what happens without synchronized added to methods

class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j &lt; 10; j++) {
Counter counter = new Counter();
List&lt;Thread&gt; list = new ArrayList&lt;&gt;();
for (int i = 0; i &lt; 100000; i++) {
list.add(new Thread(counter::increment));
list.add(new Thread(counter::decrement));
}
for (Thread item : list) {
item.start();
}
System.out.println(&quot;Results&quot;);
System.out.println(counter.value());
System.out.println(counter.value());
System.out.println(counter.value());
System.out.println(counter.value());
System.out.println(counter.value());
for (Thread item : list) {
item.join();
}
System.out.println(&quot;Results after join&quot;);
System.out.println(counter.value());
}
}
}

I did run it a few times and sometimes the results where -3 even after using join

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

发表评论

匿名网友

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

确定