简体   繁体   中英

Java Concurrency Synchronized not working

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.

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.

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());
}

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 < 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());
        }
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM