Java方法如何防止并发访问。

8
我该如何防止并发访问。我的代码如下:
public class MC implements Runnable {

    public void run() {
        sync();
    }

    public static void main(String p[]){
        MC mc = new MC();
        MC mc2 = new MC();
        MC mc3 = new MC();
        MC mc4 = new MC();
        Thread t = new Thread(mc);
            t.start();
            Thread t2 = new Thread(mc2);
            t2.start();
            Thread t3 = new Thread(mc3);
            t3.start();
            Thread t4 = new Thread(mc4);
            t4.start();
    }

    private synchronized void sync(){
        try {
            System.out.println(System.currentTimeMillis());
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

我得到了这样的输出

,与IT技术有关。
1307082622317
1307082622317
1307082622317
1307082622317
BUILD SUCCESSFUL (total time: 11 seconds)

任何建议吗?

期望的输出将会是什么? - Waldheinz
你想要实现什么目标? - trojanfoe
6个回答

13

将你的方法设为静态方法:

private static synchronized void sync();

你的代码中的方法是在实例上同步的,但每个线程都有自己的实例,因此没有同步。

静态方法在Class对象上同步,每个类只有一个Class对象,因此所有实例将在静态方法上同步。


8
你有四个单独的MC对象。通常在这些对象上运行实例方法(sync),它们不应该相互干扰。你可以使用synchronized块来确保每次只运行一个,但你需要考虑要同步什么:
- 如果你为每个实例同步到一个单独的对象上,那么就会阻止两个线程同时运行相同对象的代码。这实际上就是你现在拥有的,但我不建议你隐式地在this上同步。(任何其他代码都可以在同一对象上同步。) - 如果你在所有实例都知道的对象上同步(例如通过静态变量),那么只有一个线程能够完全运行代码。
听起来你想要后一种方法,但对我来说,这并不是很好的设计。如果你真的想以这种方式实现它,你可以使用:
public class MC implements Runnable {

    private static readonly Object lock = new Object();

    ...

    private void sync() {
        synchronized (lock) {
            try {
                System.out.println(System.currentTimeMillis());
                Thread.sleep(10000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}

保持将sync作为同步方法,但将其静态化也可以工作,但你会锁定一个公开可见的对象(MC.class),这通常是不鼓励的。

呵欠 - 看看我的答案:只需将该方法设为静态的。 - Bohemian
1
@Bohemian:正如我在答案的结尾明确指出的那样,这种方法确实可以奏效,但这意味着锁定一个公开可见的对象。在我看来,这不是一个好主意——我喜欢能够推理我的代码,知道没有其他东西可以锁定相同的对象。 - Jon Skeet
@Jon_Skeet:好的,说得对,但坦白地说,整个类都“设计不太好”,只是为了演示目的而存在,所以这个快速修复回答了他的“到底发生了什么”问题。 - Bohemian
1
@Bohemian:如果你愿意,你可以选择只是快速修复,但我宁愿质疑设计并同时提到最佳实践。我认为这样做,即使你只是打哈欠,OP也会学到更多。 - Jon Skeet
只需要这样做:synchronized (MC.class) { - Igor Mukhin
@iimuhin:这样做虽然可以“工作”,但意味着你正在使用一个可以在其他地方同步的锁。我更喜欢不要在“this”或其他外部可见引用上同步。 - Jon Skeet

4
为了实现所需的功能,您可以将同步功能设置为静态。我不会谈论设计的好处。只要按照自己喜欢的方式去做就可以了!
private static synchronized void sync()

0

您正在实例化四个对象,并且 synchronized 在不同的监视器上。要么使 sync 静态,以便实际类将成为监视器,要么在实例化时向所有四个对象传递相同的监视器对象,然后对其进行同步。


0

使用静态锁来同步您的方法。锁类位于java.concurent包内。


0

你正在创建你的类MC的新实例,同步方法保证如果它不是静态方法,则只有一个实例可以访问。

我建议你有一个私有静态变量,比如说Integer lock,然后在它上面进行同步:

private void sync() {

synchronized (lock) {

    try {
        System.out.println(System.currentTimeMillis());
        Thread.sleep(10000);
    } catch (InterruptedException ex){
        ex.printStackTrace();
    }

}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接