在Collection框架中,为什么外部同步比内部同步(Vector,HashTable等)更快?即使他们都使用相同的机制?
内部和外部同步的确切含义以及它们彼此之间有何不同?
如果有人可以用例子解释,那将非常有用。
答案 0 :(得分:9)
内部和外部同步的确切含义以及它们彼此之间有何不同?
外部同步是指调用者(您)使用synchronized
关键字或其他锁来防止多个线程访问的另一个类。如果有问题的类不自身同步,通常会使用它 - SimpleDateFormat
是一个主要的例子。如果您需要线程之间的信令 - 即使在处理并发集合时也可以使用它。
为什么外部同步比内部同步(Vector,HashTable等)快?即使他们都使用相同的机制?
外部同步不必然更快。通常,类可以精确地确定何时需要围绕代码的关键部分进行同步,而不是在synchronized
块中包含所有方法调用的调用者。
如果您正在讨论不使用Vector
和HashTable
的一般建议,而是使用Collections.synchronizedList(...)
或synchronizedMap(...)
方法,那么这是因为Vector
和HashTable
被视为旧/旧日期类。被包裹的ArrayList
或HashMap
被视为更好的解决方案。
有时候@Chris指出,当你需要一个接一个地对一个类进行一些更改时,外部同步会更快。通过外部锁定一次然后对类执行多次更改,这比每次在内部锁定的更改效果更好。单个锁比多个锁定调用快一行。
如果有人可以用例子解释,那将非常有用。
人们通常建议将Vector
包裹起来,而不是ArrayList
,而不是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();
}
的每次调用换行:
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);
}
并在内部处理它自己的重入:
{{1}}
答案 1 :(得分:7)
假设您在银行工作。每次需要使用保险箱时,都需要解锁,然后在使用保险箱后重新锁定。
现在让我们说你需要携带50个盒子进入保险箱。您有两种选择:
哪一个更快? (第一个选项是内部同步,第二个选项是外部同步。)