Рубрики
Без рубрики

Обязательно используйте общий пул Fork / Join; это потоки демонов

В java есть два вида потоков – поток пользователя и поток демона, которыми являются пользовательские потоки… Помеченный java.

В java существует два вида потоков-

  • пользовательский поток и
  • поток демона

Пользовательские потоки являются приоритетными потоками. Поток пользователя умирает, когда он завершает свою работу. Поэтому, если поток не будет прерван никакими внешними средствами, он будет жить до тех пор, пока не завершит свою работу. С другой стороны, потоки демонов создаются из потока пользователя и обслуживают поток пользователя. Таким образом, поток демона может умереть, не завершив свою работу, если умирает поток пользователя, из которого он был создан.

Программа Java начинается с основного метода, а основной метод начинается с основного потока. Давайте посмотрим на пример-

package com.bazlur;

import java.util.concurrent.TimeUnit;

public class Day024_Playground {
    public static void main(String[] args) {
        var thread = new Thread(() -> {
            while (true) {
                //this thread is supposed to be running forever
                sleep(1);
                System.out.println(Thread.currentThread().getName()
                        + " is daemon? "
                        + Thread.currentThread().isDaemon());
            }
        });

        thread.setDaemon(true);
        thread.start();

        System.out.println("Running from main method");
        sleep(5);
        System.out.println("Done! will die now");
    }

    private static void sleep(int second) {
        try {
            TimeUnit.SECONDS.sleep(second);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

В приведенном выше коде мы создали новый поток из основного метода. Поток создается из потока пользователя, который в основном является основным потоком. Внутри Потока у нас есть бесконечный цикл. Это означает, что этот поток будет работать вечно, пока он не будет остановлен внешним средством. Однако мы пометили его как поток демона. Это означает, что он будет продолжать работать до тех пор, пока основной поток жив.

Основной поток создает этот новый поток, переходит в спящий режим, затем печатает инструкцию и затем умирает. Таким образом, поток демона немедленно умрет.

Если вы запустите приведенный выше код, вы получите следующий вывод-

main method is running from Thread [main,5,main]
Running from main method
Thread-0 is daemon? true
Thread-0 is daemon? true
Thread-0 is daemon? true
Thread-0 is daemon? true
Done! will die now

Ничто больше не будет печатать уилла.

До сих пор мы узнали о потоке демона. Давайте теперь узнаем кое-что еще-

В Java появилась новая конструкция под названием CompletableFuture . Используя его, мы можем выполнить фрагмент кода асинхронно.

В нем есть несколько заводских методов, которые мы можем легко использовать. Например – RunAsync() , supplyAsync() . Пример-

    CompletableFuture future = CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
        });

Или на случай, если нам понадобится извлечь из этого пользу –

CompletableFuture meaningOfLife = CompletableFuture.supplyAsync(() -> {
    return 42;
});

Теперь вопрос в том, в каком потоке выполняются эти методы?

Ответ заключается в том, что они выполняются путем разветвления/присоединения к общему пулу.

Если вы запустите следующий код в своем основном методе-

package com.bazlur;

import java.util.concurrent.CompletableFuture;

public class Day024_Playground2 {
    public static void main(String[] args) {

        CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
            System.out.println("from " + Thread.currentThread());
        });

    }
}

Вы должны получить следующее-

Running asynchronously!
from Thread[ForkJoinPool.commonPool-worker-19,5,main]

Однако, если в вашей программе есть только приведенный выше код и ничего больше в основном методе, вы можете вообще ничего не получить. В основном методе ничего не будет напечатано.

Кажется загадочным, не так ли?

Чтобы получить результат, вам нужно либо вызвать get() в завершаемом будущем, как показано ниже-

package com.bazlur;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class Day024_Playground2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
            System.out.println("from " + Thread.currentThread());
        }).get();
    }
}

Вызов get() является блокирующим вызовом, что означает, что основной поток будет заблокирован здесь, и ничего из основного потока не будет выполняться до завершения асинхронного блока.

Если у нас есть какой-то другой код в основном потоке, они будут ждать, пока этот асинхронный блок не завершит свою работу, что, в свою очередь, уменьшает асинхронность.

Или основной поток живет дольше, чем асинхронный блок. В этом случае мы обязательно получим ожидаемый результат.

package com.bazlur;

import java.util.concurrent.CompletableFuture;

public class Day024_Playground2 {
    public static void main(String[] args) throws InterruptedException {

        CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
            System.out.println("from " + Thread.currentThread());
        });

        System.out.println("Doing some important work!");
        Thread.sleep(1000);
    }
}

Теперь, если мы запустим приведенный выше код, мы получим результат. Причина в том, что основной поток живет дольше, чем Завершаемое будущее . Предполагая, что Завершениеfuture не займет больше 1000 миллисекунд.

Из приведенного выше обсуждения мы можем сделать вывод, что ForkJoinPool.commonPool содержит потоки демона. Если бы они были пользовательскими потоками, они бы закончили свою работу; не имело бы значения, закончит ли основной поток свою работу или нет.

Давайте посмотрим, так это или нет?

package com.bazlur;

import java.util.concurrent.CompletableFuture;

public class Day024_Playground2 {
    public static void main(String[] args) throws InterruptedException {

        CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
            System.out.println("from " + Thread.currentThread());
            System.out.println("Is it a daemon thread? "+ Thread.currentThread().isDaemon());
        });

        System.out.println("Doing some important work!");
        Thread.sleep(1000);
    }
}

Ответ – поразительное “да”. Они действительно являются потоком демона.

Итак, что мы узнали из всей этой дискуссии?

Если наш основной поток не будет жить дольше, чем поток демона, мы не получим никакого результата от CompletableFuture . Это происходит потому, что они не доживут до завершения своей работы.

Что мы можем сделать, если у нас есть случай, когда несколько CompletableFuture выполняйте некоторые асинхронные задания, но пользовательский поток, из которого они создаются, умирает раньше?

Вместо использования общего пула forkJoin моим решением было бы предоставить наш собственный пул потоков. У нас есть исполнители.

package com.bazlur;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

public class Day024_Playground2 {
    public static void main(String[] args) throws InterruptedException {

        var threadPool = Executors.newCachedThreadPool();

        CompletableFuture.runAsync(() -> {
            System.out.println("Running asynchronously!");
            sleep();
            System.out.println("from " + Thread.currentThread());
        }, threadPool);

        System.out.println("I'm Done!! going to die.");
        threadPool.shutdown();
    }

    private static void sleep() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

В приведенном выше коде даже пользовательский поток умирает, это не повлияет на Завершаемое будущее ; он закончит свою работу, а затем умрет.

Если нам нужна такая гарантия, мы всегда должны предоставлять исполнителей для завершения будущего.

Это на сегодня! Ваше здоровье!

Оригинал: “https://dev.to/bazlur_rahman/be-sure-of-using-fork-join-common-pool-they-are-daemon-threads-4aac”