我正在处理某个问题,其中我有一个接口实现(由GoogleMaps tile提供程序实现),其中该方法立即需要其数据(而不是在回调中),但是对于我来说,要获取数据,我必须调用一个返回该方法的方法。回调中的数据。我必须将这2个链接在一起,并且有一些东西(我认为可以,但尚未测试),但我担心会收到一些Android Studio警告。

这是我编写的代码:

@Override
public Tile getTile(int x, int y, int zoom) {
    // If the tile provider is not available, return null
    if(tileProvider == null) {
        return NO_TILE;
    }

    // Define the tile request
    final TileRequest tileRequest = new TileRequest(tileProvider.getLayer().getTileWidth(), tileProvider.getLayer().getTileHeight());

    // Make the call to get the tile data, which, depending on the situation, can possibly
    // be handled by another thread.
    tileProvider.getTile(x, y, zoom, new GetDataListener<byte[]>() {
        @Override
        public void onGetData(byte[] data, Exception exception) {
            synchronized (tileRequest) {
                tileRequest.data = data;
                tileRequest.exceptionOccurred = exception != null;
                tileRequest.finishedRequest = true;
                tileRequest.notify();
            }
        }
    });

    synchronized (tileRequest) {
        // If, before this statement was reached, the request has already been finished, call and return getTile immediately.
        if(tileRequest.finishedRequest) {
            return tileRequest.getTile();
        } else {
            try {
                // Wait for the tileRequest to be finished
                tileRequest.wait();

                // Once it is finished (in the callback a notify is called as soon as its finished, so thats how this code is reached)
                // the tile data is available, return the tile
                return tileRequest.getTile();

            } catch(InterruptedException ex) {
                // Exception occurred, return null so GoogleMaps will try it again later
                logger.error("Exception in getTile method: {}", ex.getLocalizedMessage());
                ex.printStackTrace();
                return null;
            }
        }
    }
}


因此,Android Studio在第二行synchronized (tileRequest) {上给我的是以下警告:

Synchronization on local variable 'tileRequest'

Reports synchronization on a local variable or parameter. Such synchronization has little effect, since different threads usually will have different values for the local variable or parameter. The intent of the code will usually be clearer if synchronization on a field is used.

我对同步,等待和通知的理解不太自信,所以不管警告如何,有人可以告诉我我的方法是否有效?

编辑
有一些问题表明没有涉及多个线程,我对注释进行了一些更新,但是tileProvider.getTile(...)方法会获取切片,但不能保证不会在另一个线程上发生这种情况。

最佳答案

在某些情况下,JVM可能会忽略在本地对象上进行同步,因此,如果不进行详细分析,就无法依靠它具有正确的语义。我建议一种更简单的方法:

CountDownLatch done = new CountDownLatch(1);
tileProvider.getTile(x, y, zoom, new GetDataListener<byte[]>() {
    @Override
    public void onGetData(byte[] data, Exception exception) {
        tileRequest.data = data;
        tileRequest.exceptionOccurred = exception != null;
        tileRequest.finishedRequest = true;
        done.countDown();
    }
});

done.await();
return tileRequest.getTile();


请注意,您可能在if (tileRequest.finishedRequest) return tileRequest.getTile();之前不能有done.await(),因为您将失去闩锁提供的可见性保证。而且根据您的代码,似乎无论如何将finishRequest设置为true后,立即会解除对闩锁的阻止。

10-06 05:24