Возвращаемое значение из потока - PullRequest
3 голосов
/ 09 марта 2011

У меня есть класс потока, который читает файл из URL-адреса, а затем сохраняет результат в общедоступной статической переменной, чтобы к нему можно было получить доступ из других классов.Есть ли лучшее для достижения этой цели?

Спасибо

public class ReadContent implements Runnable{

    private HttpConnection connection;
    private InputStream inputStream;
    private String url;

    public ReadContent(String url){
        this.url = url;
    }

    public void run() {
        readContentURL();
    }

    private void readContentURL() {

        try {   
                connection = (HttpConnection)Connector.open(url);
                connection.setRequestMethod(HttpConnection.GET);
                connection.setRequestProperty("Connection", "close");
                inputStream = connection.openDataInputStream();

            //  inputStream = getClass().getResourceAsStream(url);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int c ;
                while (true) {
                    c = inputStream.read();
                    if (c == -1)
                        break;
                    baos.write(c);
                }

                SavedJSON.result = new JSONObject(new String(baos.toByteArray()));

            } 
            catch(Exception e){
                e.printStackTrace();
            }   
    }

}

Вот мое предлагаемое решение -

public class MyFuture{ 
      private final Object lock = new Object();

      private JSONObject value;
      public void set(JSONObject t){
          value = t;
          synchronized(lock){
              value = t;
              lock.notifyAll();  
          }
      }

      public JSONObject get(){
         synchronized(lock){
              while(value == null)
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

              return value;
         }

      }    
    }

public class SavedJSON {

    public static MyFuture result;
    }

public class ReadContent implements Runnable{

    private HttpConnection connection;
    private InputStream inputStream;
    private String url;

    public ReadContent(String url){
        this.url = url;
    }

    public void run() {
        readContentURL();
    }

    private void readContentURL() {

        try {   
            int len = 0;
                connection = (HttpConnection)Connector.open(url);
                connection.setRequestMethod(HttpConnection.GET);
            //  connection.setRequestProperty("Connection", "close");
                inputStream = connection.openDataInputStream();

            //  inputStream = getClass().getResourceAsStream(url);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int c ;
                while (true) {
                    c = inputStream.read();
                    if (c == -1)
                        break;
                    ++len;
                    baos.write(c);
                }

                SavedJSON.result.set(new JSONObject(new String(baos.toByteArray(), 0, len, "utf-8")));

            } 
            catch(Exception e){
                e.printStackTrace();
            }   
    }

}

Ответы [ 5 ]

2 голосов
/ 09 марта 2011

Поскольку вы не можете использовать Callable (и я полагаю, вы также не можете использовать Future), вы можете попытаться создать свое собственное Future.Это относительно просто:

public class MyFuture<T>{ // can you not use generics either?
  private final Object lock = new Object();

  private T value;
  public void set(T t){
      synchronized(lock){
          value = t;
          lock.notifyAll();  
      }
  }
  public T get(){
     synchronized(lock){
          while(value == null) lock.wait();

          return value;
     }

  }    
}

Теперь вы можете иметь SavedJSON.result быть MyFuture, и когда кто-то хочет получить значение и ему нужно подождать, он может просто вызвать SavedJSON.result.get();, и набор, очевидно, может быть SavedJSON.result.set(new JSONObject(new String(baos.toByteArray())));

Редактировать:

Это адрес вашего комментария и редактирование.

Первое: вы можете распространить прерванное исключение.Обычно потоки пытаются «остановить» другие потоки с использованием прерывания.Вы можете либо добавить в метод объявление throws, либо сгенерировать исключение времени выполнения, либо просто вернуть нулевое значение.

Второе: вы не должны иметь значение = t вне синхронизированного блока.По разным причинам это может потерпеть неудачу.Вы должны удалить эту строку, и она выглядит довольно хорошо.

1 голос
/ 09 марта 2011

Для вашего случая я предлагаю реализовать обратный вызов, например:

обратный вызов:

public interface SimpleCallback {
    public void onReceive(JSONObject data);
}

invoker:

...
SimpleCallback callback = new SimpleCallback() { 
    public void onReceive(JSONObject data) {
        // do something
    }
}
new Thread(new ReadContent(url, callback));
...

поток:

...
    // read input stream
    callback.onReceive(new JSONObject(new String(baos.toByteArray())));
} catch(Exception e){
...

надеюсь, что это поможет.

1 голос
/ 09 марта 2011

Просмотрите интерфейс Callable (для Runnable, который возвращает значение) и класс Executors для множества различных реализаций пула потоков.

0 голосов
/ 09 марта 2011

Ваш результат не синхронизирован.Вы должны улучшить свой класс SavedJSON, чтобы создать методы getResult () и setResult () и сделать их синхронизированными.Методы wait () и notify () также должны вам помочь.

0 голосов
/ 09 марта 2011

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

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html

...