在Java中,同步方法的工作原理与预期不符。

huangapple go评论72阅读模式
英文:

Synchronized method in java does not work as indended

问题

以下是翻译好的部分:

我想学习如何在Java中使用同步方法,并实现了以下代码。

public class checkThread {
    volatile int i = 0;
    
    public void increment() {
        i++;
    }
}

public class TestSync extends checkThread{
    public static void main(String[] args) {
        checkThread ct1 = new checkThread();
        Object iLock = new Object();
        for(int i = 0 ; i < 10 ; i++) {
            extracted(ct1, iLock);        
        }
    }    
    private static void extracted(checkThread ct1, Object iLock) {
        synchronized (iLock) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int a = 0; a < 1000; a++) {
                        ct1.increment();
                    }
                }
            });
            t1.start();
        }
        synchronized (iLock) {
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int a = 0; a < 1000; a++) {
                        ct1.increment();
                    }
                }
            });
            t2.start();
        }
        synchronized (iLock) {
            System.out.println(ct1.i);
        }
    }
}

然而,我得到的输出完全不是同步的!

> 1000
> 2000
> 4000
> 6000
> 8000
> 9000
> 11575
> 13575
> 15575
> 17459

为什么我会得到这样的输出,而不是1000的倍数的期望值呢?

英文:

I want to learn how to use the synchronized method in java and implemented the following code.

public class checkThread {
volatile int i = 0;
public void increment() {
i++;
}
}
public class TestSync extends checkThread{
public static void main(String[] args) {
checkThread ct1 = new checkThread();
Object iLock = new Object();
for(int i = 0 ; i &lt; 10 ; i++) {
extracted(ct1, iLock);		
}
}    
private static void extracted(checkThread ct1, Object iLock) {
synchronized (iLock) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for(int a = 0; a &lt; 1000; a++) {
ct1.increment();
}
}
});
t1.start();
}
synchronized (iLock) {
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int a = 0; a &lt; 1000; a++) {
ct1.increment();
}
}
});
t2.start();
}
synchronized (iLock) {
System.out.println(ct1.i);
}
}
}

However the output I get is not at all synchronized!

> 1000
> 2000
> 4000
> 6000
> 8000
> 9000
> 11575
> 13575
> 15575
> 17459

Why am I getting such an output and not the desired value of i in the multiples of 1000?

答案1

得分: 4

如果您想确保在另一个线程启动之前,run() 方法将由一个线程完成;那么您需要同步运行方法内部的内容,而不是线程创建部分。

在您的具体示例中,您需要拥有一个可以被两个线程访问的对象,然后获取该对象的锁。

让我通过更改您的代码添加一个示例来解释这一点;但这可能不是最佳方法;只是为了说明要点。

checkThread iLock = new checkThread();

public void someMethod() {

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (iLock) {            
                for(int a = 0; a < 1000; a++) {
                    ct1.increment();
                }
            }
        }
    });
    t1.start();
}

Thread t2 = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (iLock) {            
            for(int a = 0; a < 1000; a++) {
                ct1.increment();
            }
        }
    }
});
t2.start();

synchronized (iLock) {
    System.out.println(ct1.i);
}
}
英文:

If you are trying to make sure that the run() method will be completed by one thread before the other one start; then you need to synchronize the content inside the run method, not the thread creation part.

In your specific example, you need to have an object that can be accessed by both the threads, and then acquire the lock of that object.

Let me add an example below by changing your code; but this may not be the best way; just trying to explain the point.

checkThread iLock = new checkThread();
public void someMethod() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (iLock) {            
for(int a = 0; a &lt; 1000; a++) {
ct1.increment();
}
}
});
t1.start();
}
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (iLock) {            
for(int a = 0; a &lt; 1000; a++) {
ct1.increment();
}
}
});
t2.start();
}
synchronized (iLock) {
System.out.println(ct1.i);
}
}

huangapple
  • 本文由 发表于 2020年10月28日 01:57:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/64560279.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定