学习笔记:java多线程 JUC之四

list / set / map线程不安全

ArrayList 有序有重复

HashSet HashMap 无序无重复

hashset底层是hashmap,<k,v>中的v是固定常数,hashset的add方法,就是调用hashmapt的put方法

hashmap底层是Node类型的数组+Node类型的链表+红黑树

真正高并发系统,很少用到hashmap

 import java.util.*;
 import java.util.ArrayList;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * 题目:请举例说明集合类线程不安全
  *
  * 1 故障现象
  *   java.util.ConcurrentModificationException
  *
  * 2 导致原因
  *
  *
  * 3 解决方案
  *   1 Vector
  *   2 Collections.synchronizedList(new ArrayList<>());
  *   3 CopyOnWriteArrayList<>();
  *
  * 4 优化建议(同样的错误,不出现第2次)
  *
  *
  * 笔记:
  * 写时复刻
  * CopyOnWrite容器即写时复刻容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,
  * 复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里面添加元素,添加完元素之后,
  * 再将原容器的引用指向新的容器setArray(newElements).这样做的好处是可以对CopyOnWrite容器进行并发的读,
  * 而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,渡河写不同的容器
  */
 public class NotSafeDemo {
     public static void main(String[] args) {
         //set map 同理
         //List<String> list=new ArrayList<>();
         //List<String> list= new Vector<>();
         //List<String> list= Collections.synchronizedList(new ArrayList<>());
         List<String> list= new CopyOnWriteArrayList<>();
         Map<String,String> map=new ConcurrentHashMap<>();
         for (int i = 0; i < 30; i++) {
             new Thread(()->{
                 list.add(UUID.randomUUID().toString().substring(0,8));
                 System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
 }

Callable

获得多线程的方式:

  1. 继承Thread类

  2. 实现runable接口

  3. 实现callable接口

callable接口与runnable接口的区别:

  1. callable有返回值

  2. callable抛异常

  3. 落地方法不同 一个run 一个call

 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
 class MyThread implements Runnable
 {
     @Override
     public void run() {
    }
 }
 
 /**
  * 第三种实现多线程方法
  */
 class MyThread2 implements Callable<Integer>
 {
     @Override
     public Integer call() throws Exception {
         System.out.println("......come in here");
         try {
             TimeUnit.SECONDS.sleep(4);
        }catch (InterruptedException e){e.printStackTrace();}
         return 1024;
    }
 }
 public class CallableDemo {
     public static void main(String[] args) throws InterruptedException, ExecutionException
    {
         FutureTask futureTask = new FutureTask(new MyThread2());
         new Thread(futureTask,"A").start();
 
         System.out.println(Thread.currentThread().getName()+"----计算完成");
         System.out.println(futureTask.get());
    }
 }