Я знаю, что это распространенный вопрос с возможными дубликатами, но многие из прочитанных мной подходов не сработали для меня.
У меня есть простая программа, которая воссоздает классическую проблему синхронизации производитель-потребитель с использованием потоков.
Часть упражнения заключается в выводе информации как на консоль, так и в текстовый файл.
Мой код выглядит следующим образом:
class ProcessDemo
{
static int done = 0;
//main method to instantiate both thread processes
public static void main(String[]args) throws InterruptedException
{
final ProducerConsumer PC = new ProducerConsumer();
//instantiation of a new thread object, inside of which the run method is overridden
Thread producer = new Thread(new Runnable()
{
@Override
public void run()
{
try {
PC.produce();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
});
//instantiate second thread object, inside of which the run method is overridden
Thread consumer = new Thread(new Runnable()
{
@Override
public void run()
{
try {
PC.consume();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
});
//calling the start method to initiate both the producer and consumer threads
producer.start();
consumer.start();
}
public static class ProducerConsumer
{
int[] buffer = new int[5];
int capacity = 5;
int counter = 0;
int producerIndex = 0;
int consumerIndex = 0;
static int done = 0;
public void consume() throws InterruptedException
{
PrintWriter output = null;
try
{
//instantiating print writer object to output results to a designated file
output = new PrintWriter("results.txt");
}
catch (FileNotFoundException e1) {
e1.printStackTrace();
}
while (true)
{
long sleepTimeout = (long)(((Math.random()*2000.00)+2000.00));
Thread.sleep((long)(sleepTimeout));
System.out.println("consumer random sleep for " + sleepTimeout/1000.00 + " seconds");
output.println("consumer random sleep for " + sleepTimeout/1000.00 + " seconds");
while (producerIndex == consumerIndex && done != 1)
{
System.out.println("\n*****BUFFER EMPTY, consumer sleeping for 1 sec\n");
output.println("\n*****BUFFER EMPTY, consumer sleeping for 1 sec\n");
Thread.sleep(1000);
}
int valueRead = buffer[consumerIndex];
System.out.println("\nConsumer consumed item : " + valueRead + " from index: " + consumerIndex);
output.println("\nConsumer consumed item : " + valueRead + " from index: " + consumerIndex);
consumerIndex = (consumerIndex + 1)%capacity;
counter--;
System.out.println("counter is now: " + counter);
output.println("number of full slots in buffer: " + counter);
if (counter == 0 && done == 1)
{
System.out.println("-------------All Done---------------");
output.println("-------------All Done---------------");
break;
}
}
}
}
}
, когда я переопределяю методы run () в двух созданных мной объектах потока, а затем помещаю операторы печати внутриметод run, я смог вывести на консоль и в указанный файл, используя следующий код:
PrintWriter output = null;
try
{
output = new PrintWriter("results.txt");
}
catch (FileNotFoundException e1) {
e1.printStackTrace();
}
System.out.println("print something to console");
output.println("print something to output file");
однако при перемещении операторов print и объекта writeer из объектов потока вМетоды «производить» и «потреблять», которые я определил в отдельном классе (публичный статический класс ProducerConsumer), тогда, хотя вывод на консоль в порядке, файл вывода пуст.
В таких ситуациях я прибегал к использованию следующей техники:
outputFile = new File(outputFileName);
output_obj = new PrintStream(outputFile);
console = System.out;
System.setOut(output_obj);
System.out.println("print something to output file");
System.setOut(console);
System.out.println("print something to console");
Является ли это наилучшим способом вывода на консоль и в текстовый файл?Этот метод кажется, что он может быть не самым эффективным.Другое дело, что я должен продублировать операторы print, что добавляет большую часть моего кода, если есть лучший способ реализовать эту функциональность, мне было бы очень интересно узнать его.