gstackoverflow
gstackoverflow

Reputation: 37034

Why does my multithreaded code leads to hang?

I study java concurency.

I am trying to estimate time execution depends on thread count(read and write)

my code:

public class Task5 {
    public static int [] readerThreadCount = {1,10,100,1000};
    public static int [] writerThreadCount = {10, 1000, 1000000};


    public static void main(String[] args) throws InterruptedException {
        for (int readCount : readerThreadCount) {
            for (int writeCount : writerThreadCount) {
                System.out.println(readCount + "/" + writeCount + " = " + test(readCount, writeCount, new ArrayHolderBySynchronized()));
            }
        }

    }

    private static long test(int readCount, int writeCount, ArrayHolder arrayHolder) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(readCount + writeCount);
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < readCount; i++) {
            threads.add(new Thread(new ArrayReader(arrayHolder, countDownLatch)));
        }
        for (int i = 0; i < writeCount; i++) {
            threads.add(new Thread(new ArrayWriter(arrayHolder, countDownLatch)));

        }
        for(Thread thread:threads){
            thread.start();
        }
        countDownLatch.await();//all threads started
        long start = System.currentTimeMillis();
        for (Thread thread : threads) {
            thread.join();
        }
        return System.currentTimeMillis() - start;

    }
}

class ArrayHolderBySynchronized extends ArrayHolder {

    @Override
    public synchronized int get(int index) {
        return arr[index];
    }

    @Override
    public synchronized void write(int index, int value) {
        arr[index] = value;
    }
}

class ArrayReader implements Runnable {
    ArrayHolder arrayHolder;
    CountDownLatch countDownLatch;

    ArrayReader(ArrayHolder arrayHolder, CountDownLatch countDownLatch) {
        this.arrayHolder = arrayHolder;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        countDownLatch.countDown();
        arrayHolder.get(new Random().nextInt(ArrayHolder.ARRAY_SIZE));
    }
}

class ArrayWriter implements Runnable {
    ArrayHolder arrayHolder;
    CountDownLatch countDownLatch;

    ArrayWriter(ArrayHolder arrayHolder, CountDownLatch countDownLatch) {
        this.arrayHolder = arrayHolder;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        countDownLatch.countDown();
        arrayHolder.write(new Random().nextInt(ArrayHolder.ARRAY_SIZE), -1);
    }
}

abstract class ArrayHolder {
    public static int ARRAY_SIZE = 1_000_000;
    protected int[] arr = generateArray();

    private int[] generateArray() {
        int[] arr = new int[ARRAY_SIZE];
        for (int i = 0; i < ARRAY_SIZE; i++) {
            arr[i] = i + 1;
        }
        return arr;
    }

    public abstract int get(int index);

    public abstract void write(int index, int value);
}

it outputs

1/10 = 0
1/1000 = 1

and hangs.

I have not ideas why.

please help.

Upvotes: 1

Views: 71

Answers (1)

meriton
meriton

Reputation: 70564

It doesn't hang, starting 1000000 threads just takes 1000 times longer than starting 1000 threads (a couple minutes, on my machine):

> java Task5

1/10 = 0
1/1000 = 1
1/1000000 = 63
10/10 = 0
10/1000 = 0
10/1000000 = 60
100/10 = 0
100/1000 = 0
100/1000000 = 63
1000/10 = 0
1000/1000 = 0
1000/1000000 = 60

Your next question will likely be why your test reports a duration of 60 ms when it took minutes to execute. That's because starting a threads is far more expensive than counting down a latch, or reading from or writing to a single array element, and you only measure the latter.

Upvotes: 1

Related Questions