您的位置:首页 > 编程语言 > Java开发

【Java 高并发】并发下的ArrayList&&HashMap

2016-06-22 19:37 351 查看

    在平常的java代码开发过程中,我们会经常性的就会用到ArrayList和HashMap来辅助自己完成需求工作,而且配合的也是相当的默契。但是如果环境发生改变,在并发情况下,他是否还能够顺利的完成我们想要的要求呢??

并发下的ArrayList:

    其实对于ArrayList而言,他并非是一个线程安全的容器,如果在多线程环境下使用ArrayList,必然会导致程序出错。

public class ArrayListMultiThread {
//    ArrayList-线程不安全
static ArrayList<Integer> a1 = new ArrayList<>(10);
public static class AddThread implements Runnable {

@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
a1.add(i);
}
}
}

public static void main(String[] args) throws InterruptedException {
//        创建两个线程t1,t2
Thread t1 = new Thread(new AddThread());
Thread t2 = new Thread(new AddThread());
//        两个线程运行
t1.start();
t2.start();
//        保持顺序输出
t1.join();
t2.join();
System.out.println(a1.size());
}
}


    t1,t2两个线程同时向ArrayList中添加容器,我们期望的效果肯定是2000000.但是由于线程不安全,它真的会得到我们想要的结果吗?

情况一:由于ArrayList在扩容的过程中,内部一致性遭到了破坏,但是却没有任何工作去处理,没有得到锁的保护,使其另外一个线程看到了这样的局面,进而出现了越界的问题。最后的结果则出现了异常的情况。



情况二:两个线程同时访问,发生了肢体上的冲突,对容器的同一位置进行了同时刻的赋值,整体下来则出现了不一致的画面:



情况三:当然也有可能输出2000000,得到我们想要的结果。每次都吵架,也会有和睦相处的时候啊!真心不易。纵然有时候能够得到我们想要的结果的,但这也并非是我们想要的结果,唯一的解决方案就是更换一个“容器”,能够达到两者的永久性和睦相处,这样问题不就解决了。我们采取更换的容器为:Vector

static Vector<Integer> a1 = new Vector<>(10);



并发下的HashMap:

HashMap相比ArrayList而言,也是线程不安全的。待我们看代码细细分析:

//    定义一个HashMap集合
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() {
//            对i进行+2操作
for (int i = start; i < 100000; i += 2) {
//                赋值以2为底的无符号整数
map.put(Integer.toString(i), Integer.toBinaryString(i));
}
}
}
public static void main(String[] args) throws InterruptedException {
//        创建两个线程t1,t2
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());
}


运行到底会出什么错误?我们可以通过jstack工具来辅助查看。

    在命令窗口输入"jps",可以查阅所有的java进程,我们根据进程号,通过"jstack +"进程号""对其某个进程进行详细的查看:
为了避免进程不安全,在并发的情况下,我们可以使用ConcurrentHashMap来代替HashMap工作。

static Map<String, String> map = new ConcurrentHashMap<>();


    在并发的环境下,其实有些操作都是可以避免的,比如一些线程不安全我们完全可以用线程安全的去取代其进行工作。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: