2014-02-27 147 views
1

只爲我寫了Google Maps v2(Android)的類來組織一個移動/縮放操作的隊列。如果您知道在第一個動畫仍在運行時另一個動畫已啓動,則動畫將被取消。Java是這個類的線程安全

所以爲了避免這個問題,我寫了上課。它正在工作,但我想知道它是否安全?也許我錯過了什麼?提前致謝。

public class MapDecoratorQueue { 

    private List<MapDecorator> queue = new Vector<MapDecorator>(); 
    private boolean isRunning = false; 

    public synchronized void add(MapDecorator md) { 
     if (isRunning) { 
      queue.add(md); 
     } else { 
      queue.clear(); 
      queue.add(md); 
      next(0); 
      isRunning = true; 
     } 
    } 

    private void next(final int pos) { 
     if (queue.isEmpty()) { 
      isRunning = false; 
     } else { 
      MapDecorator decorator = queue.get(pos); 
      L.log(MapDecoratorQueue.class.getSimpleName(), "isMove: " 
        + decorator.isMove() + " isZoom: " + decorator.isZoom()); 
      if (decorator.isMove()) { 
       decorator.map.moveCamera(decorator.move); 
      } 
      if (decorator.isZoom()) { 
       decorator.map.animateCamera(decorator.zoom, 
         decorator.zoomDuration, new CancelableCallback() { 

          @Override 
          public void onFinish() { 
           queue.remove(pos); 
           next(pos); 
          } 

          @Override 
          public void onCancel() { 
           L.log(MapDecoratorQueue.class.getSimpleName(), 
             "cancelled"); 
           queue.clear(); 
           isRunning = false; 
          } 
         }); 
      } 
     } 
    } 

    public static class MapDecorator { 
     private GoogleMap map = null; 
     private CameraUpdate move = null; 
     private CameraUpdate zoom = null; 
     private int zoomDuration = 0; 

     /** 
     * Для передвижения камеры и анимации 
     * 
     * @param move 
     * @param zoom 
     * @param zoomDuration 
     */ 
     public MapDecorator(GoogleMap map, CameraUpdate move, 
       CameraUpdate zoom, int zoomDuration) { 
      this.map = map; 
      this.move = move; 
      this.zoom = zoom; 
      this.zoomDuration = zoomDuration; 
     } 

     /** 
     * Только для передвижения камеры 
     * 
     * @param move 
     */ 
     public MapDecorator(GoogleMap map, CameraUpdate move) { 
      this(map, move, null, 0); 
     } 

     /** 
     * Только для зума камеры 
     * 
     * @param zoom 
     * @param zoomDuration 
     */ 
     public MapDecorator(GoogleMap map, CameraUpdate zoom, int zoomDuration) { 
      this(map, null, zoom, zoomDuration); 
     } 

     public boolean isMove() { 
      return map != null && move != null; 
     } 

     public boolean isZoom() { 
      return map != null & zoom != null && zoomDuration >= 0; 
     } 

     public CameraUpdate getMove() { 
      return move; 
     } 

     public CameraUpdate getZoom() { 
      return zoom; 
     } 

     public int getZoomDuration() { 
      return zoomDuration; 
     } 
    } 

} 
+0

'Vector'是同步的。 – Alex

+0

我會看看'decorator.map.animateCamera',因爲回調'CancelableCallback'調用'next'函數。由於它看起來是異步的,你可能在那裏遇到問題。 –

+0

@MichaelLaffargue這是一個來自'google-play-services-lib'的方法。 [link](http://developer.android.com/reference/com/google/android/gms/maps/GoogleMap.html#animateCamera(com.google.android.gms.maps.CameraUpdate,int,com.google .android.gms.maps.GoogleMap.CancelableCallback)) – rocknow

回答

1

如果符合下面的規定,異步使用CancelableCallback,那麼當你正在泄漏對下一個(pos)方法的訪問時,你遇到了麻煩,因爲MapDecoratorQueue不是ThreadSafe。

decorator.map.animateCamera(decorator.zoom,decorator.zoomDuration, new CancelableCallback(pos)); 

反正按布賴恩戈茨:),線程安全不應該依賴於客戶implementaion(在這種情況下animatecamera),這樣你的類不是threadsafe.To使它線程安全的,你可以讓未來同步,如果你這樣做所以你不需要Vector。 ArrayList將正常工作。

1

列表(向量在你的cas)是線程安全的,但方式isRunning被使用不是。當線程嘗試使用下一個方法獲取元素時,以及另一個嘗試使用添加時添加元素時,您可以擁有競爭條件。如果第一個線程就在將isRunning設置爲false之前,而第二個線程在此時檢查它,則說明您有問題。

將同步添加到下一個方法將解決該問題。

+2

由於'next'只能用同步方法調用,所以不會有任何問題。 –

+0

我的不好,我沒有注意到它是私密的。你是絕對正確的。 – azertiti

+0

再來看看它,它也是從一個'CancelableCallback'匿名類中調用的。哪些可能被異步調用?所以你可能在這種情況下是正確的。 –