JUC并发编程

一、什么是JUC?

java原生的并发包一些常用工具类
在这里插入图片描述

二、进程线程基础回顾?

1、什么是进程和线程

进程:java.exe
线程:打字,自动保存…
总结:一个进程包含多个线程,一个进程至少有一个线程,java程序至少有两个线程:GC,Main

2、什么是并发和并行

并发:多个线程操作同一资源,交替执行的过程。
并行:多个线程同时执行,只能在多核CPU下完成。
总结:使用多线程或者并发编程的目的是为了提高效率,让CPU一直工作,得到最高处理性能。

3、线程有几种状态(通过源码分析,6种)

Q:java可以创建线程吗? A:不行!

 public enum State {
        //新建
        NEW,
 		//运行
        RUNNABLE,
 		//阻塞
        BLOCKED,
 		//等待
        WAITING,
 		//延迟等待
        TIMED_WAITING,
 		//终止
        TERMINATED;
    }

4、wait和sleep区别

注:休眠使用TimeUnit.SECONDS.sleep,和Thread.sleep没区别,单位精确!

区别waitsleep
类不同ObjectThread
是否释资源释放(睁眼谁)不释放(抱着锁睡)
使用范围不同wait和notify一组,一般在线程通信的时候用sleep就是一个单独的方法,在哪都可以用
关于异常可以不用捕获sleep需要捕获异常

三、Lock锁?

1、企业级开发需要遵循

  • 架构:高内聚,低耦合
  • 套路:线程操作资源类,资源类是单独的

1>、传统多线程

//反例!!!禁用
public class demo0011 {
    public static void main(String[] args){
        //代理模式,Ticket1被Thread代理了后启动  Ticket1被强绑定,无法复用
        //  1、不满足高内聚低耦合  2、不满足线程操作资源类
        new Thread( new Ticket1(), "A").start();
    }
}
//单独的资源类  方式  属性 高类聚  低耦合
class Ticket1 implements  Runnable{
    @Override
    public void run() {

    }
}
//正例  满足1、高内聚 低耦合   2、线程操作资源类
public class demo01 {
    public static void main(String[] args){

        Ticket ticket = new Ticket();//资源类
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    ticket.saleTiket();
                }
            }
        }, "A").start();
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    ticket.saleTiket();
                }
            }
        }, "B").start();
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    ticket.saleTiket();
                }
            }
        }, "C").start();
    }
}
//单独的资源类  只有方法,属性 可复用
class Ticket{
    private int number = 30;
    public synchronized void saleTiket(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+"线程卖出第:"+(number--)+"  还剩:"+number);
        }
    }

}

2>、使用JUC后多线程(优化)

/**
 * 学习了JUC后
 * lock锁+lambda表达式
 */
public class demo02 {
    public static void main(String[] args){
        Ticket2 ticket = new Ticket2();
        //lambda表达式 (参数)->{具体的方法实现}
        new Thread(()->{for (int i = 0; i < 20; i++) {ticket.saleTiket();}}, "A").start();
        new Thread(()->{for (int i = 0; i < 20; i++) {ticket.saleTiket();}}, "B").start();
        new Thread(()->{for (int i = 0; i < 20; i++) {ticket.saleTiket();}}, "C").start();
    }
}

//单独的资源类  方式  属性 高类聚  低耦合
class Ticket2{
    private int number = 30;
    //ReentrantLock 可重入锁 默认非公平锁
    private  Lock lock = new ReentrantLock();
    public synchronized void saleTiket(){ 
        lock.lock();
        try {
            if(number>0){
                System.out.println(Thread.currentThread().getName()+"线程卖出第:"+(number--)+"  还剩:"+number);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

2、synchronized和lock锁区别

区别synchronizedlock
表现是一个关键字是一个对象
是否可尝试获取锁无法尝试获取锁可以尝试获取锁,判断
释放锁会自动释放(a线程结束,b线程异常,也会释放)需要手动释放,否则死锁
阻塞是否一直等待线程A(获得锁如果阻塞)线程B(等待,一直等待)尝试获取锁,失败后就放弃
是否公平锁一定是非公平默认是非公平,可以通过参数设置为公平
适用场景适合代码量较小的同步问题代码量特别大,使用lock实现精准控制

3、什么是可重入锁(ReentrantLock)?

可重入锁是如果有多个锁,只要进最外面的锁,就会获得里面的所有锁,比如:ReentrantLock是可重入锁
举例理解:回家 进门 里面还有(卧室门,厨房门,书房门…)

4、什么是公平锁和非公平锁?

公平锁:公平(只能排队,后面的线程无法插队)。
非公平锁:不公平(插队,后面的线程可以插队)。
ReentrantLock默认是非公平锁,synchronized是非公平锁。

5、其他小结?

  1. lock可尝试获取锁在这里插入图片描述
  2. lock锁上锁一定要解锁且一定要包try catch,在final里解锁,否则死锁。
    在这里插入图片描述

四、生产者消费者问题?

注:线程之间本来不能通信,但是有时候需要线程之间可以协调操作,变引出生产者消费者问题

1、传统的synchronized版?

1.两个线程使用if (反例 禁用)

 /**
 * 第一个:反例  使用if
 *   传统的生产者消费者 synchronized
 *   有两个线程  A B 有一个初始值0
 *  实现两个线程交替执行  对该变量+1 -1 交替执行20次
 *  if判断会引起终端和虚假唤醒
 *  此处是两个线程可以交替执行  但是如果是多个线程呢?
 */
public class demo03 {
    public static void main(String[] args) throws InterruptedException{
        Data data = new Data();
        //lambda表达式 (参数)->{具体的方法实现}
        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "A").start();
        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "B").start();
    }
}

//单独的资源类  方式  属性 高类聚  低耦合
//线程之间通信  判断   执行   通知
class Data{
    private int number = 0;
    public synchronized void increment() throws InterruptedException {
        if(number!=0){//判断
           this.wait();
        }
        number ++;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }

    public synchronized void decrement() throws InterruptedException {
        if(number==0){//判断
            this.wait();
        }
        number --;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }
}

2.上例如果是4个线程呢可以实现交替执行吗?不能 if引起虚假唤醒
代码:

/**
 * 第二个:反例  使用if
 *   传统的生产者消费者 synchronized
 *   有两个线程  A B C D 有一个初始值0
 *  实现两个线程交替执行  对该变量+1 -1 交替执行10次
 *  if判断会引起终端和虚假唤醒
 *  此处是4个线程可以交替执行  不能交替执行  因为if值判断一次引起虚假唤醒
 *  期望结果:A B C D交替打印 1 0 1 0
 */
public class demo03 {
    public static void main(String[] args) throws InterruptedException{
        Data data = new Data();
        //lambda表达式 (参数)->{具体的方法实现}
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "D").start();
    }
}

//单独的资源类  方式  属性 高类聚  低耦合
//线程之间通信  判断   执行   通知
class Data{
    private int number = 0;
    public synchronized void increment() throws InterruptedException {
        if(number!=0){//判断
           this.wait();
        }
        number ++;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }

    public synchronized void decrement() throws InterruptedException {
        if(number==0){//判断
            this.wait();
        }
        number --;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }
}

结果
在这里插入图片描述
3. if引起虚假唤醒,官方推荐使用while(if和while区别)

在这里插入图片描述
代码

/**
 * 第三个:使用while
 *   传统的生产者消费者 synchronized
 *   有两个线程  A B C D 有一个初始值0
 *  实现两个线程交替执行  对该变量+1 -1 交替执行10次
 *  if判断会引起终端和虚假唤醒
 *  此处是4个线程可以交替执行
 *  期望结果:A B C D交替打印 1 0 1 0
 */
public class demo03 {
    public static void main(String[] args) throws InterruptedException{
        Data data = new Data();
        //lambda表达式 (参数)->{具体的方法实现}
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "D").start();
    }
}

//单独的资源类  方式  属性 高类聚  低耦合
//线程之间通信  判断   执行   通知
class Data{
    private int number = 0;
    public synchronized void increment() throws InterruptedException {
        while(number!=0){//判断
           this.wait();
        }
        number ++;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }

    public synchronized void decrement() throws InterruptedException {
        while(number==0){//判断
            this.wait();
        }
        number --;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();//通知
    }
}

结果:虽然是实现AC打1 BD打0 但是不是我们期望的 ABCD顺序打印
在这里插入图片描述
总结:wait和notifyAll不能实现精准唤醒通知

2、JUC版?

  1. 新版的写法(JUC挂钩)
    在这里插入图片描述
    注:一个Condition只绑定一个锁
    在这里插入图片描述
  2. synchronized和lock版本对比在这里插入图片描述
    3.实现精准访问
/**
 *  JUC版本  使用lock和Condition实现精准访问
 *  有三个线程  A B C 有一个初始值1
 *  期望结果:A 打印5次 B打印10次 C打印15次  交替以ABC顺序打印
 */
public class demo04 {
    public static void main(String[] args) throws InterruptedException{
        Data2 data = new Data2();
        //lambda表达式 (参数)->{具体的方法实现}
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.pint5();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.pint10();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.pint15();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }}, "C").start();
    }
}

//单独的资源类  方式  属性 高类聚  低耦合
//线程之间通信  判断   执行   通知
class Data2{
    private int number = 1;// A1   B2   C3
    private Lock lock = new ReentrantLock();
    //实现精准访问
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    public void pint5() throws InterruptedException{
        lock.lock();
        //判断
        try {
            while (number != 1){
               condition1.await();
            }
            //执行 5次
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            number = 2;
            //通知2干活
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void pint10() throws InterruptedException {
        lock.lock();
        try {
            while(number!=2){
                condition2.await();
            }
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            number = 3;
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void pint15() throws InterruptedException {
        lock.lock();
        try {
            while (number!=3){
                condition3.await();
            }
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+i);
            }
            number =1;
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

五、8锁现象?

1、8锁问题总结?

  1. 被synchronized修饰的方法,锁的对象是方法的调用者。
  2. 被static修饰的方法,锁的对象是class模板对象,全局唯一

2、8锁问题8个样例?

  1. 样例1:
/**
 * 八锁问题场景一:两个synchronized 方法
 * 两个方法调用的对象是同一个 所以先调用的先执行
 * 结果:先输出sendEmail
 */
public class demo01 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sendEmail();
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.sendSms();
        },"B").start();
    }
}
class Phone{

    public synchronized void sendEmail(){
        System.out.println("sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例2:
/**
 * 八锁问题场景二:两个synchronized 方法 其中一个延迟
 * 两个方法调用的对象是同一个 所以先调用的先执行
 * 结果:先输出sendEmail
 */
public class demo02 {
    public static void main(String[] args) throws InterruptedException {
        Phone2 phone = new Phone2();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.sendSms();
        },"B").start();
    }
}

class Phone2{

    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);//延迟4秒
        System.out.println("sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例3:
/**
 * 八锁问题场景三:一个phone 一个synchronized 方法  一个普通方法
 * sendSms是普通方法,不是同步方法,不受锁的影响
 * 结果:先输出sendSms
 */
public class demo03 {
    public static void main(String[] args) throws InterruptedException {
        Phone3 phone = new Phone3();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.sendSms();
        },"B").start();
    }
}

class Phone3{

    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);//只要此处时间大于上面main里休眠时间  一定是先执行sendSms   如果小于则先执行sendEmail
        System.out.println("sendEmail");
    }

    //普通方法(没有synchronized 没有static 修改)
    public  void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例4:
/**
 * 八锁问题场景四:两个phone
 * synchronized修饰的方法,锁的对象是锁的调用者,两个phone 所以两个锁,不受影响
 * 结果:先输出sendSms
 */
public class demo04 {
    public static void main(String[] args) throws InterruptedException {
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        new Thread(()->{
            try {
                phone1.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone2.sendSms();
        },"B").start();
    }
}

class Phone4{

    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例5:
/**
 * 八锁问题场景五:一个phone  两个static方法
 * static修饰的方法,锁的对象是方法调用者的class模板对象,这个则全局唯一,所以这里是同一个锁(先调用先执行)不是synchronized原因
 * 结果:先输出sendEmail
 */
public class demo05 {
    public static void main(String[] args) throws InterruptedException {
        Phone5 phone = new Phone5();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.sendSms();
        },"B").start();
    }
}

class Phone5{

    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例6:
/**
 * 八锁问题场景六:两个phone   两个static方法
 * static修饰的方法,锁的对象是方法调用者的class模板对象,这个则全局唯一,所以这里是同一个锁(先调用先执行)不是synchronized原因
 * 结果:先输出sendEmail
 */
public class demo06 {
    public static void main(String[] args) throws InterruptedException {
        Phone6 phone1 = new Phone6();
        Phone6 phone2 = new Phone6();
        new Thread(()->{
            try {
                phone1.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone2.sendSms();
        },"B").start();
    }
}

class Phone6{

    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例7:
/**
 * 八锁问题场景七:一个phone   一个普通同步方法  一个静态同步方法
 * static修饰的方法,锁的对象是方法调用者的class模板对象,这个则全局唯一
 * synchronized修饰的方法,锁的对象是方法调用者
 * 所以这是两个锁
 * 结果:先输出sendSms
 */
public class demo07 {
    public static void main(String[] args) throws InterruptedException {
        Phone7 phone = new Phone7();
        new Thread(()->{
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone.sendSms();
        },"B").start();
    }
}

class Phone7{

    public  synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSms(){
        System.out.println("sendSms");

    }
}
  1. 样例8:
/**
 * 八锁问题场景八:两个phone  一个静态同步方法  一个普通同步方法
 * static修饰的方法,锁的对象是方法调用者的class模板对象,这个则全局唯一
 * synchronized修饰的方法,锁的对象是方法调用者
 * 所以这是两个锁
 * 结果:先输出sendSms
 */
public class demo08 {
    public static void main(String[] args) throws InterruptedException {
        Phone8 phone1 = new Phone8();
        Phone8 phone2 = new Phone8();
        new Thread(()->{
            try {
                phone1.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone2.sendSms();
        },"B").start();
    }
}

class Phone8{

    public  synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSms(){
        System.out.println("sendSms");

    }
}

3、小结?

  1. new this 调用的这个对象,是一个具体的对象
  2. static class 唯一的一个模板

六、不安全的集合类?

注:只要是并发环境,集合都不安全(List , Set , Map)

1、List

/**
 * ArrayList.add()是没有加锁的   不安全的方法
 * ConcurrentModificationException 并发修改异常
 *解决办法:
 * 1、List<Object> list = new Vector<Object>();  使用Vector  Vector.add()是加锁的(synchronized) 弊端:Vector jdk1.0就出现了 效率低
 * 2、List<Object> list = Collections.synchronizedList(new ArrayList<>()); 使用工具类将ArrayList转换为同步的
 * 3、List<Object> list = new CopyOnWriteArrayList<>(); 使用JUC
 * 什么是CopyOnWrite 写入时赋值   读写分离   第二个线程过来写入的时候复制一个
 */
public class unsafeList {
    public static void main(String[] args) {

            //List<Object> list = new ArrayList();
            //List<Object> list = new Vector<Object>();
            //List<Object> list = Collections.synchronizedList(new ArrayList<>());
            List<Object> list = new CopyOnWriteArrayList<>();
            for (int i = 0; i < 30; i++) {
                new Thread(()-> {
                    list.add(UUID.randomUUID().toString().substring(0, 3));
                    System.out.println(list);
                },String.valueOf(i)).start();
            }
    }
}

1、CopyOnWriteArrayList:写入时复制(是一种思想COW),读写分离 ,当多个调用者同时需要一个资源,就会出现指针的概念,第二个线程过来写入的时候复制一个。
2、CopyOnWriteArrayList的add方法源码:

    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

2、Set

/**
 *  Set<Object> set =  new HashSet<Object>();  ConcurrentModificationException并发修改异常
 *  解决:
 * 1、Set<Object> set = Collections.synchronizedSet(new HashSet<Object>());
 * 2、Set<Object> set = new CopyOnWriteArraySet();
 */
public class unSafeSet {
    public static void main(String[] args) {
        //HashSet底层就是一个hashMap
        //Set<Object> set =  new HashSet<Object>();
        //Set<Object> set = Collections.synchronizedSet(new HashSet<Object>());
        Set<Object> set = new CopyOnWriteArraySet();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,3));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

3、Map

/**
 * 1、工作中new HashMap<String, String>()这么用的吗 不是 默认容量是16  超过16要扩容 需要消耗时间
 * 2、 加载因子 0.75f   容量(默认16)
 * 3、HashMap底层数据结构:链表+红黑树
 * 并发编程下使用  Map<String, String> map = new HashMap<String, String>();  引起ConcurrentModificationException并发修改异常
 * 解决方法:
 * 1、Map<String, String> map = Collections.synchronizedMap(new HashMap<String,String>());
 * 2、Map<String, String> map = new ConcurrentHashMap<String, String>();
 */
public class unSafeMap {
    public static void main(String[] args) {
        //工作中
        //Map<String, String> map = new HashMap<String, String>();
        //Map<String, String> map = Collections.synchronizedMap(new HashMap<String,String>());
        Map<String, String> map = new ConcurrentHashMap<String, String>();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,3));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

hashMap小结:
1、工作中new HashMap<String, String>()这么用的吗 不是 默认容量是16 超过16要扩容 需要消耗时间
2、 加载因子 0.75f 容量(默认16)
3、HashMap底层数据结构:链表+红黑树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值