在 Collection 框架中,为什么外部同步比内部同步(Vector、HashTable 等)快?即使他们都使用相同的机制?
内部和外部同步的确切含义是什么?它们之间有何不同?
如果有人可以举例说明,那真的很有帮助。
在 Collection 框架中,为什么外部同步比内部同步(Vector、HashTable 等)快?即使他们都使用相同的机制?
内部和外部同步的确切含义是什么?它们之间有何不同?
如果有人可以举例说明,那真的很有帮助。
内部和外部同步的确切含义是什么?它们之间有何不同?
外部同步是调用者(您)使用synchronized
关键字或其他锁来防止另一个类被多个线程访问。如果所讨论的类本身不同步,则通常使用它——SimpleDateFormat
这是一个很好的例子。如果您需要在线程之间发出信号,也可以使用它——即使在处理并发集合时也是如此。
为什么外部同步比内部同步更快(Vector、HashTable 等)?即使他们都使用相同的机制?
外部同步不一定更快。通常,一个类可以精确地确定何时需要围绕代码的关键部分进行同步,而不是调用者将所有方法调用包装在一个synchronized
块中。
如果您谈论的是不使用Vector
andHashTable
而是使用Collections.synchronizedList(...)
orsynchronizedMap(...)
方法的一般建议,那么这是因为Vector
andHashTable
被视为旧/过时的类。包裹ArrayList
或被HashMap
视为更好的解决方案。
有时正如@Chris 指出的那样,当您需要一个接一个地对一个类进行大量更改时,外部同步会更快。通过在外部锁定一次然后对类执行多次更改,这比在内部锁定每个更改更好。单个锁比连续调用多个锁要快。
如果有人可以举例说明,那真的很有帮助。
而不是Vector
,人们通常推荐 WrappedArrayList
具有更好的性能。这将非同步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
该类确实应该使用 anAtomicInteger
并在内部处理它自己的重入:
private final AtomicInteger count = new AtomicInteger(0);
public void addToCount() {
int val = count.incrementAndGet()
log.info("count increased to " + val);
}
假设你在一家银行工作。每次您需要使用保险箱时,都需要将其解锁,然后在使用完毕后重新上锁。
现在假设您需要将 50 个盒子放入保险箱。你有两个选择:
哪个更快?(第一个选项是内部同步,第二个选项是外部同步。)