开发者

Simple question on java synchronization

I would like to iterate over a java List using the old fashion for(int i...) loop, since for a given i and loop iteration, I want to access several elements relative to i. Then I can't use for(Object o: objects) neither the list iterator.

How can I ensure that no other cod开发者_高级运维e can access the list while I'm executing it?

I tried

synchronized(path.getPoints()){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

where path is the object holding the list, and also

synchronized(path){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

and also

synchronized(this){
    for (int i = 0; i < path.getPoints().size(); i++){
        ...
    }
}

where "this" is the renderer that would like to render the path quitely without synchronization issue.

Thanks in advance,

Martin


How can I ensure that no other code can access the list while I'm executing it?

By making sure that all other code also synchronizes on the same object. synchronized(path.getPoints()) is the best choice. It might be a good idea for getPoints() to return the list wrapped via Collections.synchronizedList() - then you don't need to synchronize simple get() or add() calls explicitly, but you still need the synchronization for the iteration.

Complicated? Yeah. That's why shared-memory multithreaded programming is considered very difficult.


You can avoid synchronization completely by using a copy on write approach. It has an associated cost but that may be acceptable to you: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html


You could make path.getPoints() synchronized and return a copy of the points list (or maybe an array). Then you don't need to sync while iterating over it. If points is private you can easily make sure that all the methods in Path that access it are also synchronized.


"synchronized (this)" (where "this" is your renderer) makes sure that no other thread can run the same renderer at the same time; other threads can, however, access the list and the "path" object.


Your best go at it would probably be to ensure anything that is using the collection (path.getPoints()) for writing is doing so in a synchronized block (on that same collection), so that a consumer (e.g. read-only) of that collection that wants to use an enumerator on it can do so safely by also using a synchronized block on the collection.


I would suggest you write this as.

List<Point> points = path.getPoints()
synchronized(points){
    for (Point point: points){
        ...
    }
}

This ensure getPoints() doesn't return something different and simplifies the code IMHO.

I would also use @Michaels suggestion of either synchronizing every time the getPoints() is accessed or make it a Collectons.synchronizedList() or a thread safe list like CopyOnWriteArrayList()

Note: if you use a thread safe list, you may not need to synchronize it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜