如何在线程之间异步传递引用?有观察者?

时间:2013-12-13 10:29:44

标签: java multithreading sockets asynchronous producer-consumer

我如何确保:

1。)localThreadremoteThread彼此独立运行?

2。)在localThreadremoteThread之间传递消息?

具体来说,来自localThread的String对象需要“渗透”到Telnet,我认为这是一个回调。但是,Telnetobserve本身并没有什么。这是对LocalIO的匿名引用,我没有看到明确提供引用帮助。

我读到java.util.concurrent.Semaphore直到我的头部爆炸,我所带走的是它似乎不适用。对于这两个线程,无论其他线程在做什么,它们都应该继续运行。但是,需要有一些机制来在线程之间传递对象引用...

public class Telnet {

    public Telnet() throws InterruptedException {
        startThreads();
    }

    public static void main(String[] args) throws InterruptedException {
        new Telnet();
    }

    public void startThreads() throws InterruptedException {
        Semaphore s = new Semaphore(1, true);

        Thread localThread = new Thread(new LocalIO());
        Thread remoteThread = new Thread(new RemoteIO());

        localThread.start();
        remoteThread.start();
    }
}

线程本身如下。 LocalIO

public class LocalIO implements Runnable {

    @Override
    public void run() {
        Scanner scanner;
        String line;
        while (true) {
            scanner = new Scanner(System.in);
            line = scanner.nextLine();
            out.println("\n\nyou entered\t\"" + line + "\"\n");
        }
    }
}

RemoteIO

public class RemoteIO implements Runnable {

    private static Logger log = Logger.getLogger(RemoteIO.class.getName());
    final String host = "rainmaker.wunderground.com";
    final int port = 3000;

    @Override
    public void run() {
        log.fine(host + port);
        int byteOfData;
        try (Socket socket = new Socket(host, port);
                InputStream inputStream = socket.getInputStream();
                OutputStream ouputStream = socket.getOutputStream();
                PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
                final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
            while ((byteOfData = inputStream.read()) != -1) {
                out.print((char) byteOfData);
            }
        } catch (Exception e) {
            out.println(e);
        }
    }
}

请记住,RemoteIO永远不会关闭其连接并无限期地运行。

4 个答案:

答案 0 :(得分:2)

并发包对这类事情非常有帮助: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html

例如,你可以给每个线程一个ConcurrentLinkedQueue,他们可以检查队列,看看是否有什么可以随时采取行动。同时,其他线程可以随时将新对象添加到队列中。

答案 1 :(得分:1)

您的代码可以采用的编程范例有一个本质区别:

  • 同步模式:接收端运行一个无限循环,显式从并发队列中取出项目,在没有项目准备就阻止;

  • 异步模式:接收端向项目交换机制提交回调。对于从生产者线程到达的每个项目都会调用此回调。

Observer 模式可能会松散地适用于后者,但不适用于前者。

另请注意,在后一种情况下,“项目交换机制”通常以同步模式实现。

答案 2 :(得分:1)

不确定你想要做什么,但如果你想在线程之间交换数据,你需要一个volatile变量来确保其他线程看到更改。 AtomicReferences是非阻塞的,并提供了一些可能对此有帮助的API。

答案 3 :(得分:0)

我发现的解决方案:

public class RemoteConnection extends Observable {

    private static Logger log = Logger.getLogger(RemoteConnection.class.getName());
    private final Socket socket;
    private final BufferedInputStream in;
    private final BufferedOutputStream out;
    private final static String UTF8 = "UTF-8";

    public RemoteConnection(String host, int port) throws UnknownHostException, IOException {
        socket = new Socket(host, port);
        in = new BufferedInputStream(socket.getInputStream());
        out = new BufferedOutputStream(socket.getOutputStream());
    }

    public void write(Deque<String> commands) throws IOException {
        String command;
        while (!commands.isEmpty()) {
            command = commands.pop();
            out.write(command.concat("\r\n").getBytes(Charset.forName(UTF8)));
            log.info(command);
        }
        out.flush();
    }

    void read() {  //probably should use BufferedStream to better effect..?
        Thread readRemote = new Thread() {

            @Override
            public void run() {
                StringBuilder sb = new StringBuilder();
                char ch;
                int i;
                while (true) {
                    try {
                        i = in.read();
                        ch = (char) i;
                        sb.append(ch);
                        System.out.print(ch);
                        if (i == 13) {
                            setChanged();
                            notifyObservers(sb.toString());
                            log.fine(sb.toString());
                            sb = new StringBuilder();
                        }
                    } catch (IOException ioe) {
                        log.fine(ioe.toString());
                    }
                }
            }
        };
        readRemote.start();
    }
}

通过重新组织线程,这近似于一个穷人的telnet,具有i / o的异步线程。我认为从控制台阅读是阻止......某事......

我真的不知道为什么会这样,但其他方法却没有。我宁愿让主类启动和处理线程,并在线程之间传递引用,但是尽管使用了这里提供的各种解决方案,但这样做并不起作用。

LocalConnection有类似的线程方法。