Java - 同步回调

时间:2013-12-18 13:49:27

标签: java multithreading

我有以下代码,它是异步执行的。我想让它同步,以便遵循一些逻辑流程,但我无法弄清楚如何。

您将看到scanning设置为true以指示该方法仍然有效,在开始时 - 然后我发起findPrinters(...)命令 - 这包含运行的DiscoveryHandler异步 - 每次发现一个项目时都会调用foundPrinter()discoveryFinished()是成功完成发现过程的时间,并且每当发生错误时都会调用discoveryError(...)

在我想从此方法返回之前,我依赖于在DiscoveryHandler中设置的内容。因此,为什么我下面有while (scanning)。但这对我来说就像是黑客,而不是正确的做事方式。我无法让wait()notify()工作。有人能告诉我这样做的正确方法是什么?

private boolean findPrinter(final Context ctx) {
    try {
        scanning = true;
        BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() {

            public void foundPrinter(DiscoveredPrinter device) {
                if (device instanceof DiscoveredPrinterBluetooth) {
                    DiscoveredPrinterBluetooth btDevice = (DiscoveredPrinterBluetooth) device;

                    if (btDevice.friendlyName.startsWith("XXXX")) {
                        try {
                            connection = new BluetoothConnection(btDevice.address);
                            connection.open();

                            if (connection.isConnected()) {
                                address = btDevice.address;
                            }
                        } catch (Exception ex) {

                        }
                    }
                }
            }

            public void discoveryFinished() {
                scanning = false;
            }

            public void discoveryError(String arg0) {
                scanning = false;
            }
        });
    } catch (Exception ex) {

    }

    while (scanning) {}

    return false;
}

2 个答案:

答案 0 :(得分:3)

您可以使用CountdownLatch执行此操作,java.util.concurrent可能是private boolean findPrinter(final Context ctx) { final CountdownLatch latch = new CountdownLatch(1); final boolean[] result = {false}; ... BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() { ... public void discoveryFinished() { result[0] = true; latch.countDown(); } public void discoveryError(String arg0) { result[0] = false; latch.countDown(); } ... } // before final return // wait for 10 seconds for the response latch.await(10, TimeUnit.SECONDS); //return the result, it will return false when there is timeout return result[0]; } 中最轻的同步原语:

{{1}}

答案 1 :(得分:2)

有很多方法可以做到这一点,wait()/notify()可能不是最好的,因为你可能想从异步方法中返回一些内容。因此我建议使用像BlockingQueue这样的东西。以下是如何执行此操作的简化示例:

private boolean findPrinter(final Context ctx) {
    final BlockingQueue<?> asyncResult = new SynchronousQueue<?>();
    try {
        BluetoothDiscoverer.findPrinters(ctx, new DiscoveryHandler() {

            public void foundPrinter(DiscoveredPrinter device) {
                if (device instanceof DiscoveredPrinterBluetooth) {
                    DiscoveredPrinterBluetooth btDevice = (DiscoveredPrinterBluetooth) device;

                    if (btDevice.friendlyName.startsWith("XXXX")) {
                        try {
                            connection = new BluetoothConnection(btDevice.address);
                            connection.open();

                            if (connection.isConnected()) {
                                address = btDevice.address;
                            }
                        } catch (Exception ex) {

                        }
                    }
                }
            }

            public void discoveryFinished() {
                asyncResult.put(true);
            }

            public void discoveryError(String arg0) {
                asyncResult.put(arg0);
            }
        });
    } catch (Exception ex) {
    }

    Object result = asyncResult.take();

    if (result instanceof Boolean) {
        return (Boolean) result;
    } else if (result instanceof String) {
        logError((String) result);
    }

    return false;
}

这里使用SynchronousQueue的一个问题是,如果多次调用discoveryFinished()/discoveryError(),那么异步执行代码的线程将永远阻塞,因为SynchronousQueue假设确实存在每个take()一个put(),如果put()没有相应的take(),则会阻止,反之亦然。因此,如果在您的情况下可以多次调用这些方法,您可能会使用不同类型的BlockingQueue代替documentation