19.并发下的ArrayListHashMap,Integer加锁问题

Posted fly-book

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了19.并发下的ArrayListHashMap,Integer加锁问题相关的知识,希望对你有一定的参考价值。

import java.util.ArrayList;
import java.util.Vector;

/**
 * 并发下的ArrayList
 */
public class ArrayListMultiThread 
    static ArrayList<Integer> arrayList = new ArrayList<>();
//    static Vector<Integer> arrayList = new Vector<>(); //解决方式 使用线程安全的Vector代替ArrayList
    public static class AddThread implements Runnable
        @Override
        public void run() 
//            synchronized (ArrayListMultiThread.class)  //解决方式加锁
                for (int i = 0; i < 1000000; i++) 
                    arrayList.add(i);
                
//            
        
    
    public static void main(String[] args) throws InterruptedException
        Thread thread1 = new Thread(new AddThread());
        Thread thread2 = new Thread(new AddThread());
        thread1.start();
        thread2.start();
        thread1.join();thread2.join();
        System.out.println(arrayList.size());
        //Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 10
        //  at java.util.ArrayList.add(ArrayList.java:463)
        //  at com.combat.ArrayListMultiThread$AddThread.run(ArrayListMultiThread.java:11)
        //  at java.lang.Thread.run(Thread.java:748)
        //1000001

        //这种结果是因为ArrayList在扩容过程中,内部一致性被破坏,但由于没有锁的保护,另一个线程访问到了不一致的内部状态
        //导致出现越界问题

        //结果二:2000000
        //结果二:小于2000000
    

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 并发下的HashMap
 * jdk8
 */
public class HashMapMultiThread 
    static Map<String,String> map = new HashMap<>();
//    static ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); //解决方式 用ConcurrentHashMap代替HashMap
    public static class AddThread implements Runnable
        int start = 0;
        public AddThread(int start)
            this.start = start;
        
        @Override
        public void run() 
//            synchronized (HashMapMultiThread.class) // 解决方式
                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 thread1 = new Thread(new AddThread(0));
        Thread thread2 = new Thread(new AddThread(1));
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(map.size());
        //Exception in thread "Thread-1" Exception in thread "Thread-0" java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
        //  at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1832)
        //  at java.util.HashMap$TreeNode.treeify(HashMap.java:1949)
        //  at java.util.HashMap.treeifyBin(HashMap.java:772)
        //  at java.util.HashMap.putVal(HashMap.java:644)
        //  at java.util.HashMap.put(HashMap.java:612)
        //  at com.combat.HashMapMultiThread$AddThread.run(HashMapMultiThread.java:19)
        //  at java.lang.Thread.run(Thread.java:748)
        //java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
        //  at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1832)
        //  at java.util.HashMap$TreeNode.putTreeVal(HashMap.java:2012)
        //  at java.util.HashMap.putVal(HashMap.java:638)
        //  at java.util.HashMap.put(HashMap.java:612)
        //  at com.combat.HashMapMultiThread$AddThread.run(HashMapMultiThread.java:19)
        //  at java.lang.Thread.run(Thread.java:748)
        //2778


        // 结果二:小于100000

        //JDk7会出现死循环  HashMap put()是一个迭代遍历,如同遍历链表一样,但由于多线程,链表成环了,形成死循环
    
/**
 * Integer加锁
 */
public class BadLockOnInteger implements Runnable
    public static Integer i = 0;
    static BadLockOnInteger instance = new BadLockOnInteger();

    @Override
    public void run() 
        for (int j = 0; j < 10000000; j++) 
            synchronized (i)
//            synchronized (instance) // 修改方式
                i++; //相当于 i = Integer.valueOf(i.intValue()+1);
            
        
    
    public static void main(String[] args) throws InterruptedException
        Thread thread1 = new Thread(instance);
        Thread thread2 = new Thread(instance);
        thread1.start();thread2.start();
        thread1.join();thread2.join();
        System.out.println(i);
        //12968375 小于20000000
        //java中Integer属于不变对象,一旦创建就不可能被修改
        //i++的本质是创建一个新的Integer对象,并将他的引用赋值给i
        //两个线程每次加锁可能都加在了不同的对象实例上
    

以上是关于19.并发下的ArrayListHashMap,Integer加锁问题的主要内容,如果未能解决你的问题,请参考以下文章

2.8.2 并发下的ArrayList,以及源码分析

2.8.3 并发下诡异的HashMap

高并发下获取随机字符串

Java--HashMap 在高并发下引起的死循环

java集合之ArrayListHashMap遍历

eclipse里arraylisthashmap报错