Skip to content
Advertisement

How to correctly use the Threads

I have the following task :

Create Class called: ElementsProvider(int n, List elements) that will provide N random elements into given list. Elements Provider will be an thread. Try create 4 instances, each of this instance will add 1000 random elements into the list. start all instances at once and wait until they end. print list size.

And here is what is did ,

Main:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ElementsProvider implements Runnable{
    private final List<Integer> list;
    private final int n;

    public ElementsProvider(List<Integer> list, int n){
        this.list = list;
        this.n = n;
    }

    @Override
    public void run() {
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            list.add(random.nextInt());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = new ArrayList<>();
        int n = 1000;
        ElementsProvider e1 = new ElementsProvider(list, n);
        ElementsProvider e2 = new ElementsProvider(list, n);
        ElementsProvider e3 = new ElementsProvider(list, n);
        ElementsProvider e4 = new ElementsProvider(list, n);

        Thread t1 = new Thread(e1);
        Thread t2 = new Thread(e2);
        Thread t3 = new Thread(e3);
        Thread t4 = new Thread(e4);

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

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

        System.out.println(list);
    }
}

Apparently I got that the task is not ok.

Feedback that I got is :

wrong, try to print list size, it will be different each time You run the program.

Can someone point me where I am mistaking please?

Advertisement

Answer

You proposed this change in a comment on your original question, above:

@Override
public void run() {
    synchronized (ElementsProvider.class) {
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            list.add(random.nextInt());
        }
    }
}

O.K., That will ensure that your program always prints the correct answer, but it does so by making your program effectively single-threaded. When you put the entire body of the threads’ run() method in a single synchronized block, you prevent them from running concurrently. But, running concurrently is the only reason to use threads.

You need to synchronize a smaller part of the code. The only variable that the threads share is the list. There is no reason for new Random() to be inside the synchronized block, and there is no reason for random.nextInt() to be inside it. The only thing that needs to be inside the synchronized block is the list.add() call.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement