为什么同步计数本身不起作用?
Why does synchronized on the count itself do not work?
为什么同步计数不安全?
class Increment implements Runnable{
static Integer count = new Integer(0);
public void run(){
for (int i = 0; i< 1_000_000; i++){
synchronized (count){
count ++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread one = new Thread(new Increment());
Thread two = new Thread(new Increment());
one.start();
two.start();
one.join();
two.join();
System.out.print(count);
}
}
1555622
我知道我是否会像这样放一些虚拟对象 o
class Increment implements Runnable{
static Integer count = new Integer(0);
static Object o = new Object();
public void run(){
for (int i = 0; i< 1_000_000; i++){
synchronized (o){
count ++;
}
} }
public static void main(String[] args) throws InterruptedException {
Thread one = new Thread(new Increment());
Thread two = new Thread(new Increment());
one.start();
two.start();
one.join();
two.join();
System.out.print(count);
}
}
2000000
会很安全。但我不明白为什么它对计数本身不起作用
因为锁不在变量上,而是在对象上。 Integer 是不可变的,当你增加它时你会得到一个新对象,它会替换你锁定的对象。每次线程尝试进入同步块时,它都会计算括号中的表达式以找到它应该锁定的内容。
这会造成一个线程锁定旧对象而传入线程锁定新对象的情况,您可以在同步块中有两个线程。
您的固定解决方案有效,因为所有线程都共享同一个锁并且它不会改变。
为什么同步计数不安全?
class Increment implements Runnable{
static Integer count = new Integer(0);
public void run(){
for (int i = 0; i< 1_000_000; i++){
synchronized (count){
count ++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread one = new Thread(new Increment());
Thread two = new Thread(new Increment());
one.start();
two.start();
one.join();
two.join();
System.out.print(count);
}
}
1555622
我知道我是否会像这样放一些虚拟对象 o
class Increment implements Runnable{
static Integer count = new Integer(0);
static Object o = new Object();
public void run(){
for (int i = 0; i< 1_000_000; i++){
synchronized (o){
count ++;
}
} }
public static void main(String[] args) throws InterruptedException {
Thread one = new Thread(new Increment());
Thread two = new Thread(new Increment());
one.start();
two.start();
one.join();
two.join();
System.out.print(count);
}
}
2000000
会很安全。但我不明白为什么它对计数本身不起作用
因为锁不在变量上,而是在对象上。 Integer 是不可变的,当你增加它时你会得到一个新对象,它会替换你锁定的对象。每次线程尝试进入同步块时,它都会计算括号中的表达式以找到它应该锁定的内容。
这会造成一个线程锁定旧对象而传入线程锁定新对象的情况,您可以在同步块中有两个线程。
您的固定解决方案有效,因为所有线程都共享同一个锁并且它不会改变。