Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Задача производитель-потребитель


Автор: Loginanton 2.11.2010, 13:53
Добрый день. Помогите пожалуйста сделать лабу в универ. Конкретно неполучается сделать следующее: есть следующий класс:
Код

class Buffer
{
 int data;
 void push(int a)
 {
  data = a;
 }
 int pop()
 {
  return data;
 }
}

Требуется сделать цикл (100 итераций) в котором один поток (я его назвал Writer) записывает в класс Buffer рандомное число от 1 до 9 и засыпает (Thread.sleep()) на такое число секунд, а другой поток (его я обозвал Reader) читает число из класса Buffer и к примеру выводит на экран. Т.е. должно быть так: Writer записывает в Buffer число, к примеру 4 и засыпает на 4 сек; пока Writer спит Reader должен прочесть из Buffer число и вывести его, а дальше ждать пока Writer снова не запишет в Buffer число, ну и т.д. Для синхронизации потоков (Writer и Reader) нужно использовать synchronized, wait(), notify(); а проверять пуст ли Buffer нельзя. Вот с синхронизацией и проблемы, пока никак победить немогу. Заранее благодарен за помощь.

Автор: mantracoder 2.11.2010, 14:05
Не вижу в приведенном коде даже попытки сделать синхронизацию. 

Автор: Loginanton 2.11.2010, 14:55
Вот код, который на данный момент:
Код

import java.util.*;

class Writer implements Runnable
{
    Buffer b;
    Writer(Buffer b)
    {
        this.b = b;
        Thread t = new Thread(this);
        t.start();
    }
    public void run()
    {
        Random r = new Random();
        int data;
        for(int i = 0; i < 100; i++)
        {
            data = r.nextInt(9);
            data++;
            b.setData(data);
            
            try
            {
                Thread.sleep(data*1000);
            }
            catch(InterruptedException e)
            {
                ;
            }
            
        }
    }
}

class Reader extends Thread
{
    Buffer b;
    Reader(Buffer b)
    {
        this.b = b;
        start();
    }
    public void run()
    {
        for(int i = 0; i < 100; i++)
        {
            System.out.println(i+ ": " + b.getData());
        }
    }
}

class Buffer
{
    int data;
    synchronized int getData()
    {

        int result = this.data;
        notify();
        try{ wait(); } catch (InterruptedException e) { ; }
        return result;
    }
    synchronized void setData(int data)
    {

        this.data = data;
        notify();
        try{ wait(); } catch (InterruptedException e) { ; }
    }
}

class java_5
{
    static public void main(String[] args)
    {
        Buffer b = new Buffer();
        new Writer(b);
            try
            {
                Thread.sleep(2);
            }
            catch(InterruptedException e)
            {
                ;
            }
        new Reader(b);
    }
}

Автор: mantracoder 2.11.2010, 15:08

Код

public class Sample {

    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        int iterations = 100;
        
        new Writer(buffer, iterations).start();
        new Reader(buffer, iterations).start();
    }

}


Код

public class Buffer {

    private List<Integer> store = new ArrayList<Integer>();
    
    public void push(Integer data) {
        synchronized (store) {
            store.add(data);
            store.notify();
        }
    }
    
    public Integer pop() {
        synchronized (store) {
            if (store.isEmpty()) {
                try {
                    store.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return store.remove(0);
        }
    }
    
}


Код

public class Writer extends Thread {

    private static final int MAX_RANDOM = 9;
    
    private Buffer buffer;
    
    private int iterations;
    
    public Writer(Buffer buffer, int iterations) {
        this.buffer = buffer;
        this.iterations = iterations;
    }
    
    @Override
    public void run() {
        Random random = new Random(System.currentTimeMillis());
        for (int i=0; i<iterations; i++) {
            int data = random.nextInt(MAX_RANDOM) + 1;
            System.out.println("Writer is going to write " + data);
            buffer.push(data);
            try {
                sleep(data * 1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}


Код

public class Reader extends Thread {

    private Buffer buffer;
    
    private int iterations;
    
    public Reader(Buffer buffer, int iterations) {
        this.buffer = buffer;
        this.iterations = iterations;
    }
    
    @Override
    public void run() {
        for (int i=0; i<iterations; i++) {
            int data = buffer.pop();
            System.out.println("Reader has read " + data);
        }
    }

}

Автор: Loginanton 2.11.2010, 15:25
mantracoder, это немного не то. Во первых данные в Buffer должны хранится в простом типе данных, а не в List. Во вторых нельзя проверять записано что то в Buffer или нет.

Автор: mantracoder 2.11.2010, 15:36
Цитата(Loginanton @ 2.11.2010,  15:25)
mantracoder, это немного не то. Во первых данные в Buffer должны хранится в простом типе данных, а не в List. Во вторых нельзя проверять записано что то в Buffer или нет.

1) Если значение буфера будет хранится в простом типе, то что произойдет, если Writer успеет записать в буфер более 1 значения, прежде чем Reader соизволит прочитаеть?

2) Reader не проверяет, есть ли значение в буфере. Проверяет сам Buffer, в противном случае, как вы определите, что поток должен ждать?

Сообственно, пример у вас есть, допиливайте его по своему усмотрению.

Автор: nc30 2.11.2010, 17:07
Loginanton,
Код

public class Buffer {

    public static final int COUNT = 100;
    
    private int content;
    private boolean available = false;

    public synchronized int read() {
        while (available == false) {
            try {
                System.out.println("[Buffer]: waiting for write...");
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        System.out.println("[Buffer]: " + content + " was read from buffer");
        notifyAll();
        return content;
    }

    public synchronized void write(int value) {
        while (available == true) {
            try {
                System.out.println("[Buffer]: waiting for read...");
                wait();
            } catch (InterruptedException e) {
            }
        }
        content = value;
        available = true;
        System.out.println("[Buffer]: " + value + " was written to buffer");
        notifyAll();
    }
}

Код

public class Writer extends Thread {

    private Buffer buffer;

    public Writer(Buffer buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        for (int i = 0; i < Buffer.COUNT; i++) {
            int sec = (int) Math.round(Math.random() * 9);
            System.out.println("[Writer]: trying to write " + sec + "...");
            buffer.write(sec);
            try {
                System.out.println("[Writer]: go to sleep (" + sec + " sec.)" );
                Thread.sleep(sec*1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

Код

public class Reader extends Thread {

    private Buffer buffer;

    public Reader(Buffer buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        for (int i = 0; i < Buffer.COUNT; i++) {
            System.out.println("[Reader]: trying to read...");
            buffer.read();
        }
    }
}

Код

public class Main {

    public static void main(String[] args) {
        Buffer b = new Buffer();
        Writer w = new Writer(b);
        Reader r = new Reader(b);
        
        r.start();
        w.start();
    }
}

Синхронизация всех действий происходит в объекте Buffer. Переменная available - для предотвращения дедлока.

P.S. Автор кода AntonSaburov + я подогнал немного под задачу.

Автор: Loginanton 2.11.2010, 17:17
Нужно чтобы Reader и Writer работали поочереди, как бы передавая друг другу эстафетную палочку - вот этого я лично никак добиться немогу.

Автор: nc30 2.11.2010, 18:36
Loginanton,
Они и так работают поочереди. Buffer лишь обеспечивает хранение полезного значения и безопасный доступ к нему. Не поленитесь скомпилировать код и посмотреть на результаты его работы: там все прозрачно.

Не очень понимаю, что вас конкретно не устраивает. Не нравятся методы в Buffer? Они спроектированы с учетом защиты от deadlock. Считайте их потокобезопасными сетером и гетером для хранящегося там полезного значения. Если вы переместите эти методы в потоковые классы и откроете доступ к хранящемуся в буфере значению, то ни о какой потокобезопасности говорить не придется.

Смущает обилие вывода на консоль объектом класса Buffer? Это сделано для того, чтобы вы понимали суть происходящих в программе нелинейных процессов. Разобравшись, вы можете безболезненно удалить ненужные вам вызовы println(), оставив чистую функциональность (хотя в этом случае пример потеряет в наглядности).

Удачи  smile 

Автор: alexsaltykov 3.11.2010, 09:43
Внесу свои 5 копеек
У меня без deadlock попроще конечно, но вроде работает.

Код

import java.util.Random;

public class Main{

    private static final int MAX_RANDOM = 9;
    public volatile int bufer;   

    /**
     * @param args
     */
    public static void main(String[] args) {
        Bufer bufer=new Bufer();
        Reader read=new Reader(bufer);
        Writer writer=new Writer(bufer);

        read.start();
        writer.start();                        
    }    
}



Код


public class Reader extends Thread {    
    public Bufer buf;

    
    public Reader(Bufer buffer){
     buf=buffer;     
    }
      
    @Override
    public void run() {     
        while (true){
            try {
                buf.read();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}


Код

public class Bufer {

    private volatile int bufer;

    public synchronized int read() throws InterruptedException {        
        System.out.println("[Buffer]: reading "+bufer);
        wait();
        return bufer;
    }

    public synchronized void write(int bufer) throws InterruptedException {
        System.out.println("[Buffer]: write "+bufer);
        this.bufer = bufer;        
        this.notifyAll();
        wait(bufer*1000);        
    }        
}


Код

import java.util.Random;


public class Writer extends Thread{
    
    private static final int MAX_RANDOM = 4;
    public Bufer buf;
    public Reader wr;

    public Writer(Bufer buffer){
        buf=buffer;    
    }
    
    
     @Override
     public void run() {
         Random random = new Random(System.currentTimeMillis());
         for(int i=0;i<100;i++){
                int data=random.nextInt(MAX_RANDOM) + 1;                                
                try {
                    buf.write(data);                                    
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
            }
     }
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)