为什么在 运行 下面的代码之后 count1 < count2? count1 和 count2 都应为 2000000
Why is count1 < count2 after running the following code? Both count1 and count2 should be 2000000
在JDK11中运行编译并查看结果。 sum1 是同步代码所用的时间,sum2 是 AtomicInteger 代码所用的时间。 count1是对synchronized count++的调用次数进行统计的结果。 count2 是相同数量的组合调用,但使用 AtomicInteger。计数应为 2000000,预计 sum1 > sum2(以毫秒为单位)。但是,count1 明显更少,那么调用去哪里了?
package com.charlie;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicTest extends Thread{
private volatile Integer count1 = 0;
private AtomicInteger count2 = new AtomicInteger(0);
private void method1() {
for (int i=0; i<1000; i++) {
int a = i;
}
synchronized (count1){
count1++;
}
}
private void method2() {
for (int i=0; i<1000; i++) {
int a = i;
}
count2.getAndIncrement();
}
public class Thread1 extends Thread{
public Date start = null;
public Date stop = null;
@Override
public
void run() {
start = new Date();
for(int i=0;i<1000000;i++) {
method1();
}
stop = new Date();
}
}
public class Thread3 extends Thread{
public Date start = null;
public Date stop = null;
@Override
public
void run() {
start = new Date();
for(int i=0;i<1000000;i++) {
method2();
}
stop = new Date();
}
}
static Thread1 t1 = null;
static Thread1 t2 = null;
static Thread3 t3 = null;
static Thread3 t4 = null;
static AtomicTest master = null;
public static void main(String[] args) {
AtomicTest master = new AtomicTest();
t1 = master.new Thread1();
t2 = master.new Thread1();
t3 = master.new Thread3();
t4 = master.new Thread3();
master.start();
t1.start();t2.start();t3.start();t4.start();
}
@Override
public void run() {
//stop and sum
Boolean finished = false;
while(!finished) {
try {
AtomicTest.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(t1.stop != null && t2.stop != null && t3.stop != null && t4.stop != null) {
Long sum1 = (t1.stop.getTime() - t1.start.getTime())
+ (t2.stop.getTime() - t2.start.getTime());
Long sum2 = (t3.stop.getTime() - t3.start.getTime())
+ (t4.stop.getTime() - t4.start.getTime());
finished = true;
System.out.println("sum1 =" + sum1 + "ms sum2 =" + sum2 + "ms");
System.out.println("count1 =" + count1 + " count2 =" + count2);
}
}
}
}
不要对可能重复使用的对象进行同步。如果您想了解更多,请阅读此 article。
在您的情况下,避免这种情况的一个简单解决方案是用一个空对象锁定。
private Object key = new Object();
private volatile Integer count1 = 0;
private void method1() {
for (int i=0; i<1000; i++) {
int a = i;
}
synchronized (key){
count1++;
}
}
a Java 整数是不可变的,所以当你对它使用 ++ 时,它会创建一个新对象。如果您在这些对象上进行同步,它们将具有不同的身份,因此这将不起作用。要修复它,您可以将 Integer 更改为普通 int(如果您不需要),但创建一个单独的 Object 进行同步。例如私人对象同步=新对象();从 Integer 更改为 plain int 也应该加快速度。
此作品的更改现在 github 中。谢谢 Magyar Tamas 和 Jason Splashett。
在JDK11中运行编译并查看结果。 sum1 是同步代码所用的时间,sum2 是 AtomicInteger 代码所用的时间。 count1是对synchronized count++的调用次数进行统计的结果。 count2 是相同数量的组合调用,但使用 AtomicInteger。计数应为 2000000,预计 sum1 > sum2(以毫秒为单位)。但是,count1 明显更少,那么调用去哪里了?
package com.charlie;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicTest extends Thread{
private volatile Integer count1 = 0;
private AtomicInteger count2 = new AtomicInteger(0);
private void method1() {
for (int i=0; i<1000; i++) {
int a = i;
}
synchronized (count1){
count1++;
}
}
private void method2() {
for (int i=0; i<1000; i++) {
int a = i;
}
count2.getAndIncrement();
}
public class Thread1 extends Thread{
public Date start = null;
public Date stop = null;
@Override
public
void run() {
start = new Date();
for(int i=0;i<1000000;i++) {
method1();
}
stop = new Date();
}
}
public class Thread3 extends Thread{
public Date start = null;
public Date stop = null;
@Override
public
void run() {
start = new Date();
for(int i=0;i<1000000;i++) {
method2();
}
stop = new Date();
}
}
static Thread1 t1 = null;
static Thread1 t2 = null;
static Thread3 t3 = null;
static Thread3 t4 = null;
static AtomicTest master = null;
public static void main(String[] args) {
AtomicTest master = new AtomicTest();
t1 = master.new Thread1();
t2 = master.new Thread1();
t3 = master.new Thread3();
t4 = master.new Thread3();
master.start();
t1.start();t2.start();t3.start();t4.start();
}
@Override
public void run() {
//stop and sum
Boolean finished = false;
while(!finished) {
try {
AtomicTest.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(t1.stop != null && t2.stop != null && t3.stop != null && t4.stop != null) {
Long sum1 = (t1.stop.getTime() - t1.start.getTime())
+ (t2.stop.getTime() - t2.start.getTime());
Long sum2 = (t3.stop.getTime() - t3.start.getTime())
+ (t4.stop.getTime() - t4.start.getTime());
finished = true;
System.out.println("sum1 =" + sum1 + "ms sum2 =" + sum2 + "ms");
System.out.println("count1 =" + count1 + " count2 =" + count2);
}
}
}
}
不要对可能重复使用的对象进行同步。如果您想了解更多,请阅读此 article。
在您的情况下,避免这种情况的一个简单解决方案是用一个空对象锁定。
private Object key = new Object();
private volatile Integer count1 = 0;
private void method1() {
for (int i=0; i<1000; i++) {
int a = i;
}
synchronized (key){
count1++;
}
}
a Java 整数是不可变的,所以当你对它使用 ++ 时,它会创建一个新对象。如果您在这些对象上进行同步,它们将具有不同的身份,因此这将不起作用。要修复它,您可以将 Integer 更改为普通 int(如果您不需要),但创建一个单独的 Object 进行同步。例如私人对象同步=新对象();从 Integer 更改为 plain int 也应该加快速度。
此作品的更改现在 github 中。谢谢 Magyar Tamas 和 Jason Splashett。