2016-08-23 4 views
1

В настоящее время я экспериментирую с параллелизмом в Java/JavaFX. Печать должна выполняться в другом потоке, иначе это приведет к замораживанию основного потока JavaFX в течение нескольких секунд. Сейчас моя печать выполняется с помощью этого упрощенного примера.Задачи очереди печати в отдельной отдельной теме для JavaFX

public void print(PrintContent pt) { 
    setPrintContent(pt); 

    Thread thread = new Thread(this); 
    thread.start(); 
} 

@Override 
public void run() { 
    // send content to printer 
} 

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

Большое спасибо за ваши усилия и ваше время.

+1

Обратите внимание, что, помимо проблемы отправки несколько заданий печати на принтер, код также страдает от нескольких потоков, пытающихся получить доступ к такому же состоянию. Вызывая 'setPrintContent (pt)' каждый вызов 'print (...)' собирается установить 'printContent' на другое значение; созданные вами потоки будут пытаться получить доступ к этому значению в некоторой (неопределенной) точке в будущем. Нет никакой гарантии, что фоновые потоки будут видеть правильный печатный контент. –

+0

Вы абсолютно правы. Я получаю исключения, особенно когда я отправляю 2 и более заданий печати подряд в течение очень короткого периода времени. – Chiggiddi

+0

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

ответ

1

~~> WAY 1

Вы можете реализовать свой собственный BlockingQueueread this is very useful или использовать реализацию по умолчанию с Java библиотеки tutorial

Таким образом, после прочтения ссылки выше, можно добавить метод в классе, как

public void addJob(Object job){ 
    queue.put(job); 
} 

Во-вторых вы реализуете тему, которая работает в бесконечном, а loop.Inside он вызывается метод

queue.take(); 

Когда очередь пуста этот поток блокируется в ожидании, пока не будет добавлен новый объект, так что вы не нужно беспокоиться о том, чтобы тратить время процессора.

Наконец, вы можете установить некоторые верхние границы, так что, например, очередь может содержать .. 27 элементов.

Упомяните, что в случае отказа резьбы вы должны заново создать его вручную.

~~> WAY 2 Better Approach

Вы можете использовать исполнитель интерфейс:

ExecutorService executorService1 = Executors.newSingleThreadExecutor(); 

Из документации:

Создает Исполнитель, который использует один рабочий поток, работающий с неограниченной очередью . (Обратите внимание, что если этот единственный поток завершает из-за сбоя во время выполнения до выключения, новый будет займет свое место, если это необходимо для выполнения последующих задач.) Задачи гарантированно выполняются последовательно и не более одной задачи будет активным в любой момент времени.

С помощью приведенного ниже метода вы получите результат, если задание выполнено успешно.

Future future = executorService.submit(new Callable(){ public Object call() throws Exception { System.out.println("Asynchronous Callable"); return "Callable Result"; } }); 

System.out.println("future.get() = " + future.get()); 

Если future.get() возвращает null, задание выполнено успешно.

Не забудьте позвонить executorService.shutdown();, потому что активные потоки внутри этого ExecutorService могут помешать JVM отключиться.

Полного учебник here

+0

Привет, GoXr3Plus, спасибо за ваш намек. Читая о Executer, я также столкнулся с BlockingQueue. Не могли бы вы рассказать мне, почему вы думаете, что Executer - лучший подход или в чем основное отличие этих двух? – Chiggiddi

+0

Кстати, ваши ссылки отличные и легко читаемые! – Chiggiddi

+0

@Chiggidi Реализации Executor внутренне используют какой-то BlockingQueue. Мне так хотелось, чтобы вы могли реализовать свои собственные. В конце концов, использование второго способа - это всего лишь несколько строк кода, а не реализация вашего собственного. В любом случае, все, что вам нужно знать, это по ссылкам. – GOXR3PLUS

4

Используйте single threaded executor для выполнения заданий на печать. Это создаст один (и только один) фоновый поток и очереди заданий:

// it might be better not to make this static; but you need to ensure there is 
// only one instance of this executor: 
private static final Executor PRINT_QUEUE = Executors.newSingleThreadExecutor(); 

// ... 

public void print(PrintContent pt) { 

    PRINT_QUEUE.execute(() -> { 
     // send content to printer 
    }); 
}