Gay*_*tri 5 java thread-safety
我对同步实例方法和静态方法很困惑.我想写一个线程安全类如下:
public class safe {
private final static ConcurrentLinkedQueue<Object> objectList=
new ConcurrentLinkedQueue<Object>();
/**
* retrieves the head of the object and prints it
*/
public synchronized static void getHeadObject() {
System.out.println(objectList.peek().toString());
}
/**
* creates a new object and stores in the list.
*/
public synchronized void addObject() {
Object obj=new Object();
objectList.add(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
在静态方法上同步将锁定safe.class锁,并且在实例方法上进行同步将锁定此问题,因此将达到不一致的状态.
如果我想为下面的代码片段实现一致状态,那么如何实现呢?
编辑:我假设你的意思是Queue<Object> objectList而不是ConcurrentLinkedQueue<Object> objectList. ConcurrentLinkedQueue<Object>已经为您完成了所有线程安全,这意味着您可以调用objectList.peek()您想要的所有内容,而不必担心竞争条件。如果您正在开发多线程程序,这非常有用,但对于了解线程安全性则不太好。
您的方法不需要synchronized,假设您一次有一个线程对对象的一个实例进行操作,但是如果您需要有多个类实例,并且所有实例都引用同一个静态类变量,则需要对该synchronized类进行操作像这样的变量:
public static void getHeadObject() {
synchronized(safe.objectList) {
System.out.println(objectList.peek().toString());
}
}
Run Code Online (Sandbox Code Playgroud)
这会锁定objectList,并且一旦程序位于同步块内,就不允许在任何其他线程中读取或写入它。对所有其他方法执行相同的操作synchronized。
笔记:
但是,由于您只执行一个简单的 get 操作List.peek(),因此您实际上不需要同步 ,objectList因为在竞争条件下,它将获得 的一个值List或另一个值。竞争条件的问题是当执行多个复杂的读/写操作时,并且它们之间的值发生变化。
例如,如果您有一个PairInt包含 aPairInt.x和PairInt.y字段的类,并且具有x = 2y, 和您想要执行的约束
System.out.println(myIntPair.x.toString() + ", " + myIntPair.y.toString());
Run Code Online (Sandbox Code Playgroud)
另一个线程正在同时更新x和的值,y
myIntPair.y = y + 3;
myIntPair.x = 2 * y;
Run Code Online (Sandbox Code Playgroud)
并且写入线程myIntPair在读取线程之间进行修改myIntPair.x.toString(),myIntPair.y.toString()您可能会得到类似于 的输出(10, 8),这意味着如果您的操作x == 2 * y可能会导致程序崩溃。
在这种情况下,您的读取需要使用 a synchronized,但对于更简单的事情,例如在队列中添加或删除而不是修改的peek()简单内容,在大多数情况下可以删除。事实上,对于、、等,应该删除简单读取的条件。objectsynchronizedstringintboolsynchronized
然而,写入应该始终synchronized针对非显式线程安全的操作,即已由 java 处理的操作。一旦您获取了多个资源,或者要求您的资源在执行多行逻辑时在整个操作过程中保持不变,那么您必须使用 synchronized