javamultithreadingconcurrencythread-safetyconcurrent-programming

Why do I need to synchronize this variable


I have 4 threads each trying to find the max value in a linked list.

This is my thread class:

public class MyThread extends Thread {

    LinkedList<Integer> list;
    int max = Integer.MIN_VALUE;

    public MyThread(LinkedList<Integer> list) {
        this.list = list;
    }

    public void run() {
        synchronized (list) {       /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */
            while (!list.isEmpty()) {
                int num = list.remove();

                if (num > max) {
                    max = num;
                }
            }
        }
    }
}

And here is the class with the main method:

public class Application {

    public static void main(String args[]) throws InterruptedException {
        LinkedList<Integer> list = new LinkedList<Integer>();

        for (int i = 0; i < 10; i++) {
            list.add(i);
        }

        MyThread t1 = new MyThread(list);
        MyThread t2 = new MyThread(list);
        MyThread t3 = new MyThread(list);
        MyThread t4 = new MyThread(list);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        t1.join();
        t2.join();
        t3.join();
        t4.join();

        System.out.println(t1.max);
        System.out.println(t2.max);
        System.out.println(t3.max);
        System.out.println(t4.max);
    }
}

In the above code, I have to synchronize the list variable within the run method or else I'll get a NoSuchElementException at list.remove(). Why is this the case?

Doesn't each thread have it's own list so there is no thread interference?

Thanks


Solution

  • I will address a different part of your question that @Rishi addressed:

    Doesn't each thread have it's own list so there is no thread interference?

    The simple answer is: No, it does not. In Java, when you pass an object of class type to a constructor or method, you aren't passing the obejct itself but rather a pointer to it. If you want to pass a separate copy of the linked list to each thread, you need to use LinkedList#Clone.

    If you use clone, then when a thread removes one integer from its linked list, it will not be removed from the other linked lists. To properly paralellize this, you should use a standard array with all of your numbers and assign a segment of this array to each thread (ie. thread 1 does 0-9, thread 2 does 10-19, thread 3 does 20-29, etc.). The array's contents will be visible to any threads created after the contents are deposited in the array.


    I should also note that you should not extend Thread. Instead, extend Runnable and pass it to a thread. Furthermore, an array(list) would be better than 4 separate variables as it allows you to easily change the number of threads later.