我正在尝试使用String对象作为锁(是的,我知道不推荐它 - 它仅用于锁定理解)。
在创建锁时初始化锁定时,一切正常:
代码:
public class Action{
String lock = new String("hello");
@Override
public String myAction(long threadId){
synchronized (lock) {
i++;
printToLog("thread " + threadId);
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
printToLog("Thread "+threadId+ " could not sleep "+ e.getMessage() + "\n");
}
printToLog("Thread "+threadId+ " slept well! ");
}
return i+"";
}
private void printToLog(String messege) {
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//get current date time with Date()
Date date = new Date(System.currentTimeMillis());
logger.info(messege + " at time: "+dateFormat.format(date));
}
}
日志:
[主题555时间:2015/02/18 18:16:03]
[线程555睡得很好!时间:2015/02/18 18:17:43]
[主题557时间:2015/02/18 18:17:43]
[线程557睡得很好!时间:2015/02/18 18:19:23]
[线程556时间:2015/02/18 18:19:23]
[线程556睡得很好!时间:2015/02/18 18:21:03]
但是当我在方法中初始化实例成员锁时,就好像同步不起作用。
代码:
public class Action{
String lock;
@Override
public String myAction(long threadId){
lock = new String("hello");
synchronized (lock) {
i++;
printToLog("thread " + threadId);
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
printToLog("Thread "+threadId+ " could not sleep "+ e.getMessage() + "\n");
}
printToLog("Thread "+threadId+ " slept well! ");
}
return i+"";
}
private void printToLog(String messege) {
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//get current date time with Date()
Date date = new Date(System.currentTimeMillis());
logger.info(messege + " at time: "+dateFormat.format(date));
}
}
日志:
[主题555时间:2015/02/18 19:17:35]
[主题556时间:2015/02/18 19:17:40]
[主题556时间:2015/02/18 19:17:41]
[主题557时间:2015/02/18 19:17:44]
[主题560时间:2015/02/18 19:17:48]
[线程555睡得很好!时间:2015/02/18 19:19:15]
[线程556睡得很好!时间:2015/02/18 19:19:20]
[线程556睡得很好!时间:2015/02/18 19:19:21]
[线程557睡得很好!时间:2015/02/18 19:19:24]
[线程560睡得很好!时间:2015/02/18 19:19:28]
我不明白启动对象的是什么?更多 - 它是一个字符串对象所以无论如何它不应该是相同的参考?我在想什么?
编辑:是的,我不小心交换了代码..当你的“帖子似乎包含代码格式不正确的代码”太多次然后找出它时会发生什么是由于日志行:|将修复掉期。
答案 0 :(得分:3)
(您可能已经交换了代码片段)。
我认为你错过了Java synchronization的一个重要方面。您不能使用字段 lock
作为锁定,为某个实例分配锁。或者如手册中所述:
与synchronized方法不同,synchronized语句必须指定提供内部锁的对象
那么你的第二个问题(问题代码片段中的第一个)是你创建一个新对象,即:
lock = new String("hello");
然后你锁定在该对象上。这意味着每个线程都有一个锁定的不同实例。因此根本没有同步。
示例:假设您有两个帖子t1
和t2
。首先,我们运行线程1的一部分。线程1调用该方法并创建值为String
的{{1}}实例。所以内存看起来像:
"hello"
接下来你锁定了那个对象,所以标记为+------+ +---------------+
|Action| <------------------+ thread memory |
+------+ +-------+ +---------------+
| lock------->|String |
+------+ +-------+
|"hello"|
+-------+
并带有lock
,你得到:
&
现在线程+------+ +---------------+
|Action| <------------------+ thread memory |
+------+ +-------+ +---------------+
| lock------->|String | &
+------+ +-------+
|"hello"|
+-------+
进来了。t2
做的第一件事就是创建一个新对象:
t2
因此新对象未锁定,线程+------+ +----------------+
|Action| <------------------+ thread2 memory | (old object)
+------+ +-------+ +----------------+ +-------+
| lock------->|String | |String | &
+------+ +-------+ +-------+
|"hello"| |"hello"|
+-------+ +-------+
可以继续执行。
但是,您的代码可能会部分锁定。例如,线程t2
可能首先创建一个对象,然后设置t1
的字段,然后暂停。然后Action
变为活动状态,同时创建一个对象,设置t2
字段,因此两个线程最终都使用相同的对象,但这不太可能。
最后需要注意的是,使用&#34; Action's
作为锁&#34; 有没问题。首先,你不能使用String
作为锁定,你应该将其视为&#34;锁定&#34;字符串。因此,虚拟机只是将信息附加到锁定的对象。因此,没有好的或坏对象被锁定。