有线程对象锁与类锁

时间:2012-10-15 11:43:54

标签: java multithreading

  

可能重复:
  What is the difference between synchronized and static synchronized?

对象锁定类锁的优点是什么?

例如,

 public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);  
       }
    }

public void log2(String msg1, String msg2){
       synchronized(this){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }

3 个答案:

答案 0 :(得分:1)

如果在类上创建锁,则该类的所有实例将共享锁。如果您有1个实例,则不会有任何差异。如果您有数千个实例,它们都将使用完全相同的锁。如果许多线程同时尝试获取锁,它们将相互阻塞。在最坏的情况下,这可能会导致您的代码表现得好像根本没有线程。

如果在实例上创建锁,则只要多个线程在不同的实例上运行,就可以执行受保护的代码。这里,线程不会相互阻塞。所以这种方法表现更好。

但这不是你需要问的问题。真正的问题是:我需要什么样的锁?

如果要确保只有一个线程可以写入日志,则应在log上进行同步。这种方法的另一个优点是,当您开始使用多个日志文件(例如,每个线程一个)时,它将自动正常工作。

答案 1 :(得分:0)

它们不可互换,因为它们锁定不同的物体。

如果锁定对象是合适的,请使用它。如果你想锁定一个类(这不太可能),你会使用它。

我会考虑这种组合。

public void log2(String msg1, String msg2){
    synchronized(this) {
        synchronized(log) {
            log.writeln(msg1);
            log.writeln(msg2);
        }
    }
}

这将确保不修改对象,并且行在日志中一起显示。

但是,由于log2似乎没有使用可变字段,您可以使用

private final Log log = ...

public void log2(String msg1, String msg2){
    synchronized(log) {
        log.writeln(msg1);
        log.writeln(msg2);
    }
}

答案 2 :(得分:0)

从下面给出的Logger类中,如果Log类被修改为使用Lock对象,则调用log(String msg1,String msg2)的线程将使用其新的同步策略对线程安全的日志执行操作。但是调用log(String msg1)方法的线程将始终在Log实例上同步,并且Log类中的所有Lock对象将一次保留。在这种情况下,Logger的实现会中断。这就是为什么建议使用私有的最终Lock对象或Lock类而不是客户端锁定。

public class Logger {
    private final Log log;
    private final Object lock = new Object();

    public Logger(Log log) {
        this.log = log;
    }

    public void log(String msg1) {            // log synchronizes on log instance
        synchronized (log) {        
            log.writeln(msg1);      
        }
    }

    public void log(String msg1, String msg2) {   // log uses private final lock
        synchronized (lock) {
            log.writeln(msg1);
                        log.writeln(msg2);  
        }
    }   
}