【问题标题】:Why can my synchronized methods lock on different objects?为什么我的同步方法可以锁定不同的对象?
【发布时间】:2017-04-02 15:22:23
【问题描述】:

我现在正在学习 Java 并发。我遇到了这样一段代码:

package pac1;

import java.util.*;
import java.util.concurrent.*;

class A1 {
    public void f() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("f()");
        }
    }
}

class B1 {
    public void g() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("g()");
        }
    }
}

class C1 {
    public void p() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("p()");
        }
    }

}

public class V {
    public static void main(String[] args) {
        A1 a = new A1();
        B1 b = new B1();
        C1 c = new C1();
        new Thread() {
            public void run() {
                a.f();
            }
        }.start();
        new Thread() {
            public void run() {
                c.p();
            }
        }.start();
        b.g();
    }

}

由于这段代码使用不同的对象来调用同步方法,我认为它不会阻止它们相互干扰。但是,结果如下:

f()
f()
f()
f()
f()
g()
g()
g()
g()
g()
p()
p()
p()
p()
p()

顺便说一句,使用Lock的结果是一样的:

package pac1;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class A {
    Lock lock = new ReentrantLock();

    public void f() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("f()");
        } finally {
            lock.unlock();
        }
    }
}

class B {
    Lock lock = new ReentrantLock();

    public void g() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("g()");
        } finally {
            lock.unlock();
        }
    }
}

class C {
    Lock lock = new ReentrantLock();

    public void p() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("p()");
        } finally {
            lock.unlock();
        }
    }
}

public class Ex16 {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        new Thread() {
            public void run() {
                a.f();
            }
        }.start();
        new Thread() {
            public void run() {
                c.p();
            }
        }.start();
        b.g();
    }

}

【问题讨论】:

  • 尝试打印更多内容。我怀疑Java在设置第二个线程的方法时完成了第一个线程的方法,然后在那个真正开始之前它已经完成了main方法的运行,所以你可以按1、3、2的顺序打印它们。我敢打赌,如果你每个都做 1000 个,他们就会搞混了。
  • 是什么让您认为它们相互干扰?在每次迭代时添加对 Thread.sleep(500) 的调用。

标签: java concurrency thread-safety synchronized


【解决方案1】:

这里不需要锁或同步。同步用于锁定对共享可变状态的访问。您一开始就没有任何共享的可变状态。

这里有 3 个线程,由于上下文切换,没有人可以预测这些线程的运行顺序。我看不出有什么问题。

【讨论】:

    【解决方案2】:

    实际上,循环根本不够长,因此允许线程以它们启动的相同顺序完成。为了明确线程不会干扰,您可以尝试以下方法之一:

    • 使循环运行时间更长,例如1000 次迭代应该足够了:

      synchronized (this) { for (int i = 0; i < 1000; i++) System.out.println("f()"); }

    • 暂停循环中的线程,但确保为每个循环设置不同的间隔:

      synchronized (this) { for (int i = 0; i < 5; i++) { System.out.println("p()"); try { Thread.sleep(3000); } catch (final InterruptedException ex) { // Swallow } } }

    长话短说:这些锁实际上不会干扰。

    【讨论】:

      猜你喜欢
      • 2023-04-04
      • 2012-09-06
      • 2019-02-08
      • 2018-04-14
      • 2011-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多