我很想知道如何在Unix中实现与线程之间的同步相关的函数.例如,当我打电话时会发生什么pthread_mutex_lock?有没有使用指针?对源代码的引用确实会有所帮助.
我碰巧发表了一篇文章,最近讨论了Java中的双重检查锁定模式及其陷阱,现在我想知道我多年来一直使用的那种模式的变体是否会受到任何问题的影响.
我已经查看了很多关于这个主题的帖子和文章,并了解了获取对部分构造对象的引用的潜在问题,据我所知,我认为我的实现不受这些问题的影响.以下模式是否有任何问题?
而且,如果没有,为什么人们不使用它?我在这个问题的任何讨论中都没有看过它.
public class Test {
private static Test instance;
private static boolean initialized = false;
public static Test getInstance() {
if (!initialized) {
synchronized (Test.class) {
if (!initialized) {
instance = new Test();
initialized = true;
}
}
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud) java singleton multithreading synchronization double-checked-locking
我在Java中有这个代码:
public void doSomeThing() {
synchronized (this) {
doSomeThingElse();
}
}
public void doSomeThingElse() {
synchronized (this) {
// do something else
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码能阻止吗?我的意思是,这段代码可以等待吗?
我们发现在代码中我们有几个位置,其中并发读取受互斥锁保护的数据是相当常见的,而写入很少见.我们的测量结果似乎表明,使用简单的互斥锁严重阻碍了读取数据的代码的性能.所以我们需要的是多读/单写互斥.我知道这可以建立在更简单的原语之上,但在我尝试自己之前,我宁愿要求现有的知识:
从简单的同步原语中构建多读/单写锁的批准方法是什么?
我确实知道如何制作它,但我宁愿通过我(可能是错误的)想出的答案而不偏不倚.(注意:我期望的是如何解释它,可能是伪代码,而不是完整的实现.我当然可以自己编写代码.)
注意事项:
这需要有合理的表现.(我想到的是每次访问需要两次锁定/解锁操作.现在可能不够好,但需要其中许多操作似乎是不合理的.)
通常,读取数量更多,但写入比读取更重要且性能更敏感.读者不能让作家们挨饿.
我们被困在一个相当古老的嵌入式平台(VxWorks 5.5的专有变体)上,有一个相当旧的编译器(GCC 4.1.2)和boost 1.52 - 除了大多数依赖于POSIX的boost部分,因为POSIX没有完全实现在那个平台上.可用的锁定原语基本上是几种信号量(二进制,计数等),我们已经在其上创建了互斥量,条件变量和监视器.
这是IA32,单核.
为什么这个测试程序导致了java.lang.IllegalMonitorStateException?
public class test {
static Integer foo = new Integer(1);
public static void main(String[] args) {
synchronized(foo) {
foo++;
foo.notifyAll();
}
System.err.println("Success");
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at test.main(test.java:6)
Run Code Online (Sandbox Code Playgroud) 关于Singletons的维基百科文章提到了一些在Java中实现结构的线程安全方法.对于我的问题,让我们考虑具有冗长初始化过程并且同时被许多线程所占据的单身人士.
首先,这个未提及的方法是否是线程安全的,如果是这样,它会同步什么?
public class Singleton {
private Singleton instance;
private Singleton() {
//lots of initialization code
}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
其次,为什么以下实现线程在初始化时是安全且懒惰的?如果两个线程同时进入该getInstance()方法会发生什么?
public class Singleton {
private Singleton() {
//lots of initialization code
}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
Run Code Online (Sandbox Code Playgroud)
最后,在第二个示例中,如果一个线程首先获取实例而另一个线程获取实例并尝试在构造函数在第一个线程中完成之前对其执行操作,该怎么办?那你可以进入一个不安全的状态吗?
我在多线程环境中聚合键的多个值.钥匙事先不知道.我以为我会这样做:
class Aggregator {
protected ConcurrentHashMap<String, List<String>> entries =
new ConcurrentHashMap<String, List<String>>();
public Aggregator() {}
public void record(String key, String value) {
List<String> newList =
Collections.synchronizedList(new ArrayList<String>());
List<String> existingList = entries.putIfAbsent(key, newList);
List<String> values = existingList == null ? newList : existingList;
values.add(value);
}
}
Run Code Online (Sandbox Code Playgroud)
我看到的问题是,每次运行此方法时,我都需要创建一个新的实例,ArrayList然后将其丢弃(在大多数情况下).这似乎是无理滥用垃圾收集器.是否有一种更好的,线程安全的方法来初始化这种结构而不必使用synchronize该record方法?我对使该putIfAbsent方法不返回新创建的元素的决定感到有些惊讶,并且缺少一种延迟实例化的方法,除非它被调用(可以这么说).
我有一个"简单"的4类示例,可以在多台计算机上可靠地显示java同步的意外行为.正如你可以在下面看到的那样,给定java sychronized关键字的契约,Broke Synchronization永远不应该从类TestBuffer中打印出来.
以下是将重现问题的4个类(至少对我而言).我对如何修复这个破碎的例子并不感兴趣,而是为什么它首先打破了.
这是我运行时获得的输出:
java -cp . SyncTest
Before Adding
Creating a TestBuffer
Before Remove
Broke Synchronization
1365192
Broke Synchronization
1365193
Broke Synchronization
1365194
Broke Synchronization
1365195
Broke Synchronization
1365196
Done
Run Code Online (Sandbox Code Playgroud)
更新:@Gray有一个最简单的例子,到目前为止.他的例子可以在这里找到:奇怪的JRC比赛条件
基于我从其他人那里获得的反馈,看起来问题可能发生在Windows 64和OSX上的Java 64位1.6.0_20-1.6.0_31(不确定更新的1.6.0)上.没有人能够在Java 7上重现该问题.它还可能需要多核机器来重现该问题.
原始问题:
我有一个类提供以下方法:
我把问题简化为下面的两个函数,这两个函数都在同一个对象中,它们都是synchronized.除非我弄错了,否则永远不应该打印"Broke Synchronization",因为在输入insideGetBuffer之前应始终将其设置为false remove.但是,在我的应用程序中,当我有1个线程调用重复删除而另一个重复调用getBuffer时,它正在打印"Broke Synchronization".症状是我得到了ConcurrentModificationException.
Java中的synchronized方法和synchronized块之间有什么区别?
我一直在网上搜索答案,人们似乎对这一个如此不确定:-(
我的看法是两者之间没有区别,除了同步块可能在范围内更加局部化,因此锁定的时间会更短?
如果是静态方法上的Lock,那么Lock是什么?锁定类的含义是什么?
java multithreading synchronization synchronized synchronized-block
尝试可视化和理解同步.
代码A.
public class MyClass1 {
private static final Object lock = new Object();
public MyClass1() {
//unsync
synchronized(lock) {
//sync
}
//unsync
}
}
Run Code Online (Sandbox Code Playgroud)
代码B.
public class MyClass2 {
private final Object lock = new Object();
public MyClass2() {
//unsync
synchronized(lock) {
//sync
}
//unsync
}
}
Run Code Online (Sandbox Code Playgroud)
注意
上面的代码显示了构造函数,但您可以在静态方法和非静态方法中讨论行为的不同之处.另外,当synchronized块修改静态成员变量时,使用静态锁是否有利?
我已经在这个问题中查看了答案,但不清楚不同的使用场景是什么.