Использование Объекта Dataoutputstream В Порожденном Классе (thread)

Тема в разделе "Java", создана пользователем Nodit, 27 янв 2014.

  1. Nodit

    Nodit New Member

    Регистрация:
    27 янв 2014
    Сообщения:
    1
    Симпатии:
    0
    Добрый день.
    Есть код, порождающий класс и потом пытающийся использовать объекты порожденного класса.
    Код (Text):
        //Класс потока
    class ClntMove extends Thread
    {
    public DataInputStream in;
    public DataOutputStream out;
    String ServerIp;
    int ServerPort;
    Socket clientSocket=null;
    public boolean wolk = true;
    static String inMessage;
    public ClntMove(String Ip, int Port)
    {ServerIp = Ip;
    ServerPort = Port;
    this.start();
    }

    public void run ()
    {String Message;
    try {
    clientSocket = new Socket(ServerIp,ServerPort);
    in = new DataInputStream(clientSocket.getInputStream());
    out = new DataOutputStream(clientSocket.getOutputStream());
    Message="testMSG";
    out.writeUTF(Message);
    Message=in.readUTF();
    while (!clientSocket.isClosed())
    {while(wolk)
    {
    ...рабочий исполняемый код
    }
    }
    clientSocket.close();
    }
    catch (UnknownHostException ex) {Logger.getLogger(ClntMove.class.getName()).log(Level.SEVERE, null, ex);}
    catch (IOException | InterruptedException ex) {Logger.getLogger(ClntMove.class.getName()).log(Level.SEVERE, null, ex);}
    }
    }


    //Главный класс
    class ClientMLSP
    {static ClntMove Move;
    static boolean live = true;
    static boolean event = false;


    static void SelectPoint(ClntMove aMove)
    {boolean temp=true;
    try {
    String Message="ClientMSG";
    aMove.out.writeUTF(Message);[b]В оригинальном скрипте строка 142[/b]
    Message=aMove.in.readUTF();
    System.out.println(Message);
    }
    catch (UnknownHostException ex) {Logger.getLogger(ClientMLSP.class.getName()).log(Level.SEVERE, null, ex);}
    catch (IOException ex) {Logger.getLogger(ClientMLSP.class.getName()).log(Level.SEVERE, null, ex);}
    catch (InterruptedException ex) {Logger.getLogger(ClientMLSP.class.getName()).log(Level.SEVERE, null, ex);}

    }

    //Главный блок
    public static void main (String[] args) throws InterruptedException
    {String ServerIp="127.0.0.1"; //IP сервера
    int SPort_Move=50000; //Порт для связи с сервером
    Move=new ClntMove(ServerIp,SPort_Move);
    while (live)
    {
    while (!event)
    {SelectPoint(Move);[b]В оригинальном скрипте строка 183[/b]
    }
    }
    }
    }

    В двух слова. В классе ClientMLSP создается объект класса ClntMove. Move=new ClntMove(ServerIp,SPort_Move);
    ClntMove - независимый поток, который исправно выполняет возложенные на него функции обмена с сервером данными. Там все отлично работает.
    после создания объекта Move я из класса ClntMlsp пытаюсь воспользоваться открытыми сокетными соединениями с сервером и получить оттуда некоторые данные. Для этого используется процедура ClntMLSP.SelectPoint и в нее, если я правильно понял материалы статей, передается ссылка на объект Move, созданные чуть ранее.
    Внутри процедуры пытаюсь передать тестовые данные серверу
    String Message="ClientMSG";
    aMove.out.writeUTF(Message);
    и получаю ошибку.
    Exception in thread "main" java.lang.NullPointerException
    at ClntBody.ClientMLSP.SelectPoint(ClientMLSP.java:142)
    at ClntBody.ClientMLSP.main(ClientMLSP.java:183)

    Про прогоне кода в режиме отладки ошибка не возникает. Как понимаю, при штатном запуске в SelectPoint я пытаюсь использовать еще не активированный DataOutputStream, который успевает активироваться при прогоне кода в режиме отладки.
    Вопрос - каким образом можно дождаться активации DataOutputStream в параллельно выполняемом потоке и, в идеале, временно перехватывать контроль над ним, чтобы избежать возможности одновременной попытки загрузки в него данных разными потоками?
     
  2. LuMee

    LuMee Well-Known Member

    Регистрация:
    2 май 2006
    Сообщения:
    477
    Симпатии:
    0
    Идея сделать out и in в ClntMove крайне неудачна: при таком подходе о нормальной синхронизации можно забыть.

    Поэтому первым шагом будет сделать эти поля закрытыми (private или protected), а в ClntMove добавить публичные методы, через которые эти потоки можно читать/писать:
    Код (Text):
    private DataInputStream in = null;
    private DataOutputStream out = null;

    public String read() {
    return in.readUTF();
    }

    public void write(String msg) {
    out.writeUTF(msg);
    }
    Следующим шагом будет обеспечение синхронизации: нельзя давать работать с потоками ввода/вывода до их инициализации. Тут можно использовать такой подход:
    1. завести некий объект-монитор для синхронизации;
    2. при попытке получить доступ к стриму блокировать текущий поток через объект-монитор, если стрим еще не инициализирован;
    3. после инициализации стримов оповещать всех через монитор, что можно писать/читать.
    В коде это будет выглядеть примерно так (все в классе ClntMove):
    Код (Text):
    private final Object lock = new Object();

    public void run() {
    synchronized(lock) {
    clientSocket = new Socket(ServerIp, ServerPort);
    in = new DataInputStream(clientSocket.getInputStream());
    out = new DataOutputStream(clientSocket.getOutputStream());

    // Оповещаем ожидающие потоки, что стримы готовы к употреблению
    lock.notifyAll();
    }

    // Ну и далее, что там требуется сделать
    }

    public void write(String msg) {
    synchronized(lock) {
    // Ждем готовности стримов
    while(out == null) {
    try {
    lock.wait();
    } catch(InterruptedException) {
    // Поток был прерван, пока ждал. Обработать по вкусу.
    }
    }

    out.write(msg);
    }
    }
    Добавлено: Разумеется, этот код - лишь демонстрация концепции, его еще надо доработать. В частности, надо продумать, как поступать в следущих ситуациях:
    1. Сокет открыть не удалось, notifyAll не вызвался, в итоге метод write блокируется навсегда. Можно либо предусмотреть какие-то таймауты, либо флаги успешной/неуспешной инициализации и т.п.
    2. Что делать, если поток был прерван (interrupt()) во время ожидания доступности стрима: выйти из метода, еще подождать и т.п.
    3. Что-то еще, что мне сейчас с ходу не пришло в голову, но может стать проблемой :)
     
Загрузка...
Похожие Темы - Использование Объекта Dataoutputstream
  1. MartinSez06
    Ответов:
    1
    Просмотров:
    278
  2. lmike
    Ответов:
    5
    Просмотров:
    548
  3. ESWANT
    Ответов:
    1
    Просмотров:
    804
  4. solomonec
    Ответов:
    1
    Просмотров:
    1.424
  5. JohnLemon
    Ответов:
    0
    Просмотров:
    537

Поделиться этой страницей