1. 并发下的ArrayList
ArrayList是一个线程不安全的容器,多线程使用会导致错误,如下面代码。
public class ArrayListMultiThread {
public static ArrayList<Integer> al = new ArrayList<>();
public static class AddThread implements Runnable {
@Override
public void run() {
for(int i=0; i<100000; i++) {
al.add(i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AddThread());
Thread t2 = new Thread(new AddThread());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(al.size());
}
}
改进的方法只需要将ArrayList换成Vector。
2. 并发下的HashMap
HashMap也不是线程安全的,多线程并发访问时也会遇到意想不到的错误,甚至是死锁。
public class HashMapMultiThread {
public static Map<String, String> map = new HashMap<>();
public static class AddThread implements Runnable {
int start = 0;
public AddThread(int start) {
this.start = start;
}
@Override
public void run() {
for(int i=start; i<100000; i+=2) {
map.put(Integer.toString(i), Integer.toBinaryString(i));
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new HashMapMultiThread.AddThread(0));
Thread t2 = new Thread(new HashMapMultiThread.AddThread(1));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(map.size());
}
}
改进的方法是使用ConcurrentHashMap代替HashMap。
3. 错误的加锁
如下计数功能有一个隐晦的错误。
public class BadLockOnInteger implements Runnable{
public static Integer i = 0;
static BadLockOnInteger instance = new BadLockOnInteger();
@Override
public void run() {
for(int j=0; j<100000; j++) {
synchronized (i) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
在Java中,Integer属于不变对象,即1和2是两个不同的Integer对象的值,底层调用了Integer.valueOf(),而这个方法是生成一个新的Integer对象,因此两个线程加的锁加到了不同的对象上,从而导致临界区代码控制出现问题。可将synchronized (i)替换成synchronized (instance)。