0

My task: I need to generate BASE (array) of matrix in multiple threads. It can happen that thread won't make matrix at all so I'm try to limit the lifetime of each thread.


My thought: I made volatile array that contains my matrix generation tasks and made ConcurrentHashMap that contains thread and information class (index in task array and time of thread creation)


My problem: I got NullPointerException when I tried to deal with array

Thread information class:

public class ThreadInformation {
    private long timeCreated;
    private int automatIndex;

    public ThreadInformation (long timeCreated, int automatIndex) {
        this.timeCreated = timeCreated;
        this.automatIndex = automatIndex;
    }

    public long getTimeCreated() {
        return timeCreated;
    }

    public int getIndex() {
        return automatIndex;
    }
}

MultiThread class:

public class MultiTaskGenerator {
    private final int BASE_SIZE = 10;
    private final Automat[] BASE = new Automat[BASE_SIZE];

    private static final int THREAD_COUNT = 8;
    private final int THREAD_LIVE_TIME_SEC = 10;

    private Map<Thread, ThreadInformation> threads = new ConcurrentHashMap<>();
    private volatile GeneratorTask[] tasks = new GeneratorTask[THREAD_COUNT];

    private int automatReady = 0;

    MultiTaskGenerator() {
        getThreadResult();
    }

    private void initThreads() {
        for (int i = 0; i < THREAD_COUNT; i++) {
            int j = i;
            System.out.println("Thread №" + j + " started");
            threads.put(new Thread(() -> {
                tasks[j] = new GeneratorTask();
            }), new ThreadInformation(System.currentTimeMillis(), j));
        }
        startThreads();
    }

    private void initNewThread(int index) {
        for (int i = 0; i < tasks.length; i++) {
            if (i == index) {
                threads.put(new Thread(() -> {
                    tasks[index] = new GeneratorTask();
                }), new ThreadInformation(System.currentTimeMillis(), index));
            }
        }
    }

    private void startThreads() {
        for (Thread thread : threads.keySet()) {
            Thread.State state = thread.getState();
            if (state == Thread.State.NEW) {
                thread.start();
            }
        }
    }

    private void getThreadResult() {
        initThreads();
        for (int i = 0; i < tasks.length; i++) {
            System.out.println(tasks[i]);
        }
        while (automatReady < BASE_SIZE) {
            Set mapSet = threads.entrySet();
            Iterator iterator = mapSet.iterator();
            while (iterator.hasNext()) {
                Map.Entry<Thread, ThreadInformation> mapEntry = (Map.Entry)iterator.next();

                if (!mapEntry.getKey().isAlive()) {
                    if (automatReady == BASE_SIZE) continue;
                    int currentIndex = mapEntry.getValue().getIndex();

                    BASE[automatReady] = tasks[currentIndex].getAutomat();
                    System.out.println("Добавлен автомат № " + automatReady);
                    automatReady++;
                    System.out.println("Thread №" + mapEntry.getValue().getIndex() + " finished successfully");
                    iterator.remove();
                    initNewThread(mapEntry.getValue().getIndex());
                    startThreads();
                    System.out.println("Thread №" + mapEntry.getValue().getIndex() + " started");
                } else {
                    if ((System.currentTimeMillis() - mapEntry.getValue().getTimeCreated()) < (THREAD_LIVE_TIME_SEC * 1000)) continue;
                    int taskIndex = mapEntry.getValue().getIndex();
                    tasks[taskIndex].stopGeneration(true);
                    System.out.println("Thread №" + taskIndex + " stoped");
                    mapEntry.getKey().interrupt();
                    iterator.remove();
                    System.out.println("Thread №" + taskIndex + " started");
                    initNewThread(mapEntry.getValue().getIndex());
                    startThreads();
                }
            }
        }
        threads.clear();
    }

    public Automat[] getBASE() {
        return BASE;
    }
}

StackTrace:

Thread №0 started
Thread №1 started
Thread №2 started
Thread №3 started
Thread №4 started
Thread №5 started
Thread №6 started
Thread №7 started
null
null
null
null
null
null
null
null
Exception in thread "main" java.lang.NullPointerException
    at ru.stsz.MultiTaskGenerator.getThreadResult(MultiTaskGenerator.java:78)
    at ru.stsz.MultiTaskGenerator.<init>(MultiTaskGenerator.java:19)
    at ru.stsz.MainApp.main(MainApp.java:6)

Can anyone give me advise how to fix this?

Y2Kot
  • 17
  • 9
  • 2
    Please post the stacktrace error to have help. – Lorelorelore May 11 '18 at 09:31
  • 1
    Use of the `volatile` keyword can only guarantee safe publication of primitive fields, object references, or fields of immutable object referents. Array is none of the listed above. – J-Alex May 11 '18 at 09:37
  • @Lorelorelore I added stacktrace. – Y2Kot May 11 '18 at 09:41
  • You set the values of `tasks` in separate threads, but you try to access `tasks` immediately in the main thread. You have nothing in your code that waits for your threads to be finished, so there is no way to ensure that `tasks` is properly initialized. – Max Vollmer May 11 '18 at 09:44
  • @MaxVollmer so what i should change array for? I don't use getBase() for now because I can't fill base. I just call new MultiTaskGenerator() in main – Y2Kot May 11 '18 at 09:44
  • @MaxVollmer As I wrote some of the threads (in fact most of them) won't ever stops so I need to stop them forcibly – Y2Kot May 11 '18 at 09:49

1 Answers1

0

You can Add an assertion each time you need to access your arrays! something like that in the case of emty arrays:

public static void notEmpty(@Nullable Object[] array,String message) {
        if (ObjectUtils.isEmpty(array)) {
            throw new IllegalArgumentException(message);
        }
    }
A ELKAS
  • 146
  • 1
  • 5
  • Can you explain me why I'm getting null in array? Because as I understand its must be a link to the object threre, doesn't it? If I don't get an object I won't be able to stop it via my flag in this line - tasks[taskIndex].stopGeneration(true); – Y2Kot May 11 '18 at 09:36