Метод действия JSF не завершается, если был запущен новый поток [duplicate]

Если мы рассмотрим общие сценарии, в которых может быть выбрано это исключение, доступ к свойствам с объектом вверху.

Пример:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

здесь, если адрес имеет значение null, то вы получите NullReferenceException.

Итак, в качестве практики мы всегда должны использовать проверку нуля, прежде чем обращаться к свойствам в таких объектах (особенно в общих)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
43
задан Dmitry Chornyi 28 May 2011 в 11:56
поделиться

3 ответа

Введение

Истеризация потоков из управляемого управляемого сеанса компонента не обязательно является хаком, если она выполняет задание, которое вы хотите. Но нерестовые потоки при необходимости должны выполняться с особой осторожностью. Код не должен записываться таким образом, чтобы один пользователь мог, например, создать неограниченное количество потоков за сеанс и / или продолжить работу потоков даже после того, как сеанс будет уничтожен. Это рано или поздно взорвет ваше приложение.

Код должен быть написан таким образом, чтобы вы могли убедиться, что пользователь может, например, никогда не создавать более одного фонового потока за сеанс и гарантировать поток чтобы прерваться всякий раз, когда сессия будет уничтожена. Для выполнения нескольких задач в сеансе вам необходимо поставить в очередь задачи.

Кроме того, все эти потоки должны предпочтительно обслуживаться общим пулом потоков, чтобы вы могли наложить ограничение на общее количество порожденных потоков на уровне приложения. Средний сервер приложений Java EE предлагает пул потоков, управляемый контейнером, который вы можете использовать, среди прочих, EJB @Asynchronous и @Schedule . Чтобы быть независимым от контейнера, вы также можете использовать Util Concurrent ExecutorService и ScheduledExecutorService для Java 1.5.

Ниже приведены примеры Java EE 6+ с EJB.

Огонь и забыть задачу в форме submit

@Named
@RequestScoped // Or @ViewScoped
public class Bean {

    @EJB
    private SomeService someService;

    public void submit() {
        someService.asyncTask();
        // ... (this code will immediately continue without waiting)
    }

}
@Stateless
public class SomeService {

    @Asynchronous
    public void asyncTask() {
        // ...
    }

}

Асинхронно извлекать модель при загрузке страницы

@Named
@RequestScoped // Or @ViewScoped
public class Bean {

    private Future<List<Entity>> asyncEntities;

    @EJB
    private EntityService entityService;

    @PostConstruct
    public void init() {
        asyncEntities = entityService.asyncList();
        // ... (this code will immediately continue without waiting)
    }

    public List<Entity> getEntities() {
        try {
            return asyncEntities.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new FacesException(e);
        } catch (ExecutionException e) {
            throw new FacesException(e);
        }
    }
}
@Stateless
public class EntityService {

    @PersistenceContext
    private EntityManager entityManager;

    @Asynchronous
    public Future<List<Entity>> asyncList() {
        List<Entity> entities = entityManager
            .createQuery("SELECT e FROM Entity e", Entity.class)
            .getResultList();
        return new AsyncResult<>(entities);
    }

}

Если вы используете библиотечную утилиту JSF OmniFaces , это можно сделать еще быстрее, если вы аннотируете управляемый компонент с помощью @Eager .

Расписание фоновых заданий при запуске приложения

@Singleton
public class BackgroundJobManager {

    @Schedule(hour="0", minute="0", second="0", persistent=false)
    public void someDailyJob() {
        // ... (runs every start of day)
    }

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void someHourlyJob() {
        // ... (runs every hour of day)
    }

    @Schedule(hour="*", minute="*/15", second="0", persistent=false)
    public void someQuarterlyJob() {
        // ... (runs every 15th minute of hour)
    }

    @Schedule(hour="*", minute="*", second="*/30", persistent=false)
    public void someHalfminutelyJob() {
        // ... (runs every 30th second of minute)
    }

}

Непрерывно обновлять модель приложения в фоновом режиме

@Named
@RequestScoped // Or @ViewScoped
public class Bean {

    @EJB
    private SomeTop100Manager someTop100Manager;

    public List<Some> getSomeTop100() {
        return someTop100Manager.list();
    }

}
@Singleton
@ConcurrencyManagement(BEAN)
public class SomeTop100Manager {

    @PersistenceContext
    private EntityManager entityManager;

    private List<Some> top100;

    @PostConstruct
    @Schedule(hour="*", minute="*/1", second="0", persistent=false)
    public void load() {
        top100 = entityManager
            .createNamedQuery("Some.top100", Some.class)
            .getResultList();
    }

    public List<Some> list() {
        return top100;
    }

}

См. также:

42
ответ дан Community 25 August 2018 в 06:15
поделиться

Проверьте EJB 3.1 @Asynchronous methods. Это именно то, для чего они предназначены.

Небольшой пример использования OpenEJB 4.0.0-SNAPSHOT. Здесь у нас есть @Singleton компонент с одним методом, отмеченным @Asynchronous. Каждый раз, когда этот метод вызывается кем-либо, в этом случае ваш управляемый bean-компонент JSF, он немедленно возвращается независимо от того, сколько времени действительно принимает метод.

@Singleton
public class JobProcessor {

    @Asynchronous
    @Lock(READ)
    @AccessTimeout(-1)
    public Future<String> addJob(String jobName) {

        // Pretend this job takes a while
        doSomeHeavyLifting();

        // Return our result
        return new AsyncResult<String>(jobName);
    }

    private void doSomeHeavyLifting() {
        try {
            Thread.sleep(SECONDS.toMillis(10));
        } catch (InterruptedException e) {
            Thread.interrupted();
            throw new IllegalStateException(e);
        }
    }
}

Вот небольшой тестовый файл, который вызывает @Asynchronous метод несколько раз подряд.

Каждый вызов возвращает объект Future , который по существу запускает empty и позже будет иметь свое значение, заполненное контейнером, когда вызов соответствующего метода фактически завершается

import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class JobProcessorTest extends TestCase {

    public void test() throws Exception {

        final Context context = EJBContainer.createEJBContainer().getContext();

        final JobProcessor processor = (JobProcessor) context.lookup("java:global/async-methods/JobProcessor");

        final long start = System.nanoTime();

        // Queue up a bunch of work
        final Future<String> red = processor.addJob("red");
        final Future<String> orange = processor.addJob("orange");
        final Future<String> yellow = processor.addJob("yellow");
        final Future<String> green = processor.addJob("green");
        final Future<String> blue = processor.addJob("blue");
        final Future<String> violet = processor.addJob("violet");

        // Wait for the result -- 1 minute worth of work
        assertEquals("blue", blue.get());
        assertEquals("orange", orange.get());
        assertEquals("green", green.get());
        assertEquals("red", red.get());
        assertEquals("yellow", yellow.get());
        assertEquals("violet", violet.get());

        // How long did it take?
        final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);

        // Execution should be around 9 - 21 seconds
        assertTrue("" + total, total > 9);
        assertTrue("" + total, total < 21);
    }
}

Пример исходного кода

Под обложками, что делает эту работу, является:

  • JobProcessor, вызывающий не видит на самом деле экземпляр JobProcessor. Скорее это подкласс или прокси-сервер, у которого все методы переопределены. Методы, которые должны быть асинхронными, обрабатываются по-разному.
  • Вызовы асинхронного метода просто приводят к созданию Runnable, которое обертывает метод и параметры, которые вы указали. Эта runnable предоставляется Executor , которая является просто рабочей очередью, прикрепленной к пулу потоков.
  • После добавления работы в очередь проксированная версия метода возвращает реализацию из Future, который связан с Runnable, который теперь ожидает в очереди.
  • Когда Runnable, наконец, выполняет метод на экземпляре real JobProcessor , он примет возвращаемое значение и установит его в Future, сделав его доступным для вызывающего.

Важно отметить, что объект AsyncResult, возвращаемый JobProcessor, не является тот же объект Future, который удерживает вызывающий объект. Было бы здорово, если бы реальный JobProcessor мог просто вернуться String, а версия JobProcessor вызывающего абонента могла вернуться Future<String>, но мы не видели никакого способа сделать это, не добавляя дополнительной сложности. Таким образом, AsyncResult представляет собой простой объект-оболочку. Контейнер вытащит String, выбросит AsyncResult, а затем String в real Future, который удерживает вызывающий абонент.

To получите прогресс на этом пути, просто передайте потокобезопасный объект, например AtomicInteger , к методу @Asynchronous и периодически обновляйте его компонентом с кодом процента.

50
ответ дан David Blevins 25 August 2018 в 06:15
поделиться

Я пробовал это и отлично работал с моим управляемым bean-файлом JSF

ExecutorService executor = Executors.newFixedThreadPool(1);

@EJB
private IMaterialSvc materialSvc;

private void updateMaterial(Material material, String status,  Location position) {

    executor.execute(new Runnable() {
        public void run() {
            synchronized (position) {
                // TODO update material in audit? do we need materials in audit?
                int index = position.getMaterials().indexOf(material);
                Material m = materialSvc.getById(material.getId());
                m.setStatus(status);
                m = materialSvc.update(m);
                if (index != -1) {
                    position.getMaterials().set(index, m);
                }

            }
        }
    });

}

@PreDestroy
public void destory() {
    executor.shutdown();
}
-4
ответ дан Sacky 25 August 2018 в 06:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: