内部和外部同步的确切含义以及它们之间的区别是什么?
外部同步是调用者(您)使用synchronized 关键字或其他锁来防止另一个类被多个线程访问。如果所讨论的类本身不同步,则通常使用它——SimpleDateFormat 就是一个很好的例子。如果您需要在线程之间发出信号,也可以使用它——即使在处理并发集合时也是如此。
为什么外部同步比内部同步更快(Vector、HashTable 等)?即使它们都使用相同的机制?
外部同步不一定更快。通常,一个类可以准确地确定何时需要围绕代码的关键部分进行同步,而不是调用者将所有方法调用包装在 synchronized 块中。
如果您谈论的一般建议不使用Vector 和HashTable,而是使用Collections.synchronizedList(...) 或synchronizedMap(...) 方法,那么这是因为Vector 和@ 987654329@ 被视为旧的/过时的类。封装的 ArrayList 或 HashMap 被视为更好的解决方案。
有时正如@Chris 所指出的,当您需要一个接一个地对一个类进行大量更改时,外部同步会更快。通过在外部锁定一次然后对类执行多次更改,这比在内部锁定每个更改更好。单个锁比连续调用多个锁要快。
如果有人可以举例说明,那真的很有帮助。
人们通常推荐使用包装好的 ArrayList 而不是 Vector,因为它具有更好的性能。这会将非同步的ArrayList 类包装在一个外部同步它的包装类中。
List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());
总体而言,就内部与外部而言,请考虑以下类,您希望允许多个线程同时使用它:
public class Foo {
private int count;
public void addToCount() {
count++;
log.info("count increased to " + count);
}
}
您可以使用外部同步并将对addToCount() 的每个调用包装在synchronized 块中:
synchronized (foo) {
foo.addToCount();
}
或者类本身可以使用内部同步并为您进行锁定。这执行得更好,因为 logger 类不必是锁的一部分:
public void addToCount() {
int val;
synchronized (this) {
val = ++count;
}
// this log call should not be synchronized since it does IO
log.info("count increased to " + val);
}
当然,Foo 类在这种情况下确实应该使用 AtomicInteger 并在内部处理自己的重入:
private final AtomicInteger count = new AtomicInteger(0);
public void addToCount() {
int val = count.incrementAndGet()
log.info("count increased to " + val);
}