【问题标题】:Lock threads only if access same method of the same object仅当访问同一对象的相同方法时才锁定线程
【发布时间】:2018-05-25 10:40:36
【问题描述】:

我有一个带有多线程项目常用方法的对象。一些方法是同步的。我的问题是当一个线程访问同步方法而另一个线程访问另一个同步方法时。这将使一个线程等待另一个线程。我只想在访问相同的同步方法时锁定线程,但我不知道如何。我最近发现了关键字同步。

这是我的一种方法。

public synchronized static void writeError(Exception err){

    String time = longDate();//here will get personalized current date
                             //longDate is not synchronized.

    try {

        FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

        err.printStackTrace(new PrintWriter(path));

        path.flush();

    } catch (IOException e) {}

}

对这种方法有什么想法吗?

【问题讨论】:

  • 那么是时候让您了解一下多线程和锁定的一般知识了。您找到了synchronized,但您知道您可以在其他地方使用它,而不仅仅是在方法定义中吗?
  • 我知道我可以在 synchronized(Obj){...} 等方法块中使用它
  • ..Obj 有什么意义?
  • 您的方法是静态的,所以发生的事情是因为同步类 obj 被锁定而不是实例对象。所以你不能调用属于该类的其他方法。
  • 为每个需要为synchronized 的块组合创建一个单独的锁定对象,正如@Kayaman 所暗示的那样

标签: java multithreading synchronized


【解决方案1】:

所以synchronized 总是需要一个对象来操作。共享同一对象的所有synchronized互斥(即一次只有一个线程可以进入该块)。将synchronized 放在方法声明中是简写,例如方法等于synchronized(this),静态方法等于synchronized(Foo.class)(其中Foo 是包含静态方法的类)。

知道了这一点,您就可以轻松地创建多个要同步的对象,控制哪些方法可以同时运行,哪些不能。

示例类,允许method3与method1或method2同时运行,但是method1和method2是互斥的。此外,一次只能有一个线程运行每个方法。

public class Foo {
    private final static Object lock1 = new Object();
    private final static Object lock2 = new Object();

    public static void method1() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method2() {
        synchronized(lock1) {
            ...
        }
    }

    public static void method3() {
        synchronized(lock2) {
            ...
        }
    }
}

还要注意静态与非静态。这里方法是静态的,锁是静态的,所以一切都很好。如果方法是非静态的,它也会阻止在不同的对象上调用方法,这可能不是你想要的。在这种情况下,使锁成为非静态将使每个Foo 实例如前所述工作,但在foo1.method1()foo2.method2() 的情况下不会锁定,因为它们不会在同一个对象上同步.

正如 Shubham Kadlag 的回答所示,synchronized 远非 Java 拥有的唯一并发工具。 java.util.concurrent.locks 包具有用于锁定的类(而 synchronized 是一种内置机制)。例如,ReentrantReadWriteLock 允许您处理多个线程可以同时执行某些操作(读取)但一次只允许一个线程执行修改操作(写入)的情况。它们还允许您为锁定设置超时,而synchronized 将愉快地等待(不是tryLock() 通常是必需的,因为如果您遇到死锁,这是一个编程错误)。

然后您意识到手动锁定无论如何都是针对笨蛋的,并发现java.util.concurrent 有许多类可以对您隐藏锁定并提供各种高级功能。

【讨论】:

  • 使用 ReentrantLock 不是比使用手动对象锁更好吗?
  • @ShubhamKadlag 在什么方面更好?如果您需要额外的功能,那么肯定synchronized 不会这样做,但考虑到OP 刚刚发现synchronized 并且他的用例似乎很简单,使用Lock 没有任何优势。跨度>
  • @raul1ro 添加了一些额外的故事。
【解决方案2】:

正如Kamayan 所说,对象同步将满足您的需求。

此外,如果您有性能问题或您有大量线程,您可以申请锁。

参考https://dzone.com/articles/synchronized-vs-lock

正如上面的帖子所指出的,同步最适合访问锁的少量线程 (

您可以参考http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/ 了解不同的锁示例。

为所有方法创建一个单独的锁,如下所示。

private static ReentrantLock writeErrorlock = new ReentrantLock();

        public static void writeError(Exception err){
            writeErrorlock.lock();
            String time = longDate();//here will get personalized current date
                                     //longDate is not synchronized.

            try {

                FileWriter  path = new FileWriter("ERROR - " + time + ".txt",true);

                err.printStackTrace(new PrintWriter(path));

                path.flush();

            } catch (IOException e) {

            }
            finally {
                writeErrorlock.unlock();
            }

        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2015-07-06
    • 2011-12-31
    相关资源
    最近更新 更多