面试题目:
下面的方法是线程安全吗?如果让它变为线程安全?
class MyCounter {
private static int counter = 0;
public static int getCount() {
return counter++;
}
}
这篇文章来解释一个常被Google和其他许多公司问到的面试题目。它是低级的,与如何设计并发程序无关。
首先,答案是否定的。这个方法不是线程安全的,因为counter++操作不是原子的,这意味着它由超过一个原子操作组成。这个例子中,一个是访问值,一个是在这个值上增加1.
当线程1在t1时间访问这个方法的时候,线程2 也许还没完成这个方法。所以在线程1中被返回的值是没有被增加的值。
使线程安全-方法1
在这个方法上添加synchronized将使它线程安全。当synchronized添加在一个静态方法时,Class对象是被锁定的对象。
标记方法是否足够同步?答案是Yes。
class MyCounter {
private static int counter = 0;
public static synchronized int getCount() {
return counter++;
}
}
如果方法不是静态的,添加synchronized关键字将同步这个类的实例而不是类对象本身。
使线程安全-方法二
在这个特别例子中,我们实际上可以通过使用"java.util.concurrent.atomic"包中的AutomicInteger来创建count++原子操作。
import java.util.concurrent.atomic.AtomicInteger;
public class MyCounter {
private static AtomicInteger counter = new AtomicInteger(0);
public static int getCount() {
return counter.getAndIncrement();
}
}
关于线程安全的其他事实
本地变量在Java中是线程安全的。
每个线程都有自己的栈。两个不同的线程不共享相同的栈。所有在方法中定义的本地变量都在栈中被分配内存。一旦当前线程完成,堆栈帧将被删除。