JUC并发编程(一)

JUC并发编程(一)

一. 什么是JUC

 java.util.concurrent
 java.util.concurrent.atomic
 java.util.concurrent.locks

同属于Java.util 工具包

在业务中:用普通的线程代码 Thread(普通的线程类)
Runnable 没有返回值、效率相比入 Callable相对较低!
所以,企业中Runnable用的比较少,更多的是Callable

之前学的callable 与lock都是 java.util 包下的

在这里插入图片描述
在这里插入图片描述

二. 进程和线程回顾

进程:一个程序,QQ.exe 等等程序的集合
一个进程往往包含多个线程,至少包含一个!
Java默认有多少个线程? 两个:main线程,GC线程
对于Java而言,用Runnable,Thread,Callable 来开启线程

Java真的可以开启线程吗?
答案是:不能,本质上是调用本地方法(底层的C++),Java无法直接操作硬件

并发,并行

并发编程:并发,并行
并发:交替执行,一核cpu模拟出来多个线程,

并行:一起执行,多核cpu,多个线程可以同时执行,线程池

public class Demo01 {
    public static void main(String[] args) {
        //获取CPU线程数
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}
---------------结果---------------
8

并发编程的本质:充分利用CPU资源

线程有几个状态

//我们进入枚举类,可以看到有六个状态
public enum State {
        //新建
        NEW,
 		//运行
        RUNNABLE,
         //阻塞
        BLOCKED,
		//等待,死死的等
        WAITING,
		//超时等待
        TIMED_WAITING,
		//终止
        TERMINATED;
    }

wait 和 sleep 的区别

  1. 来自不同的类
    wait 属于Object类 sleep 属于Thread 类
  2. 关于锁的释放
    wait会释放锁,sleep不会释放
  3. 使用范围不同
    wait必须在同步代码块中使用
    sleep在任何地方都能用

三. Lock锁(重点)

1. 传统Synchronized

//基本的买票例子
/**
 * 真正的多线程开发,公司中的开发,降低耦合性
 * 线程就是一个单独的资源类,没有任何附属的操作
 * 1.属性 方法
 */
public class Demo01 {
    public static void main(String[] args) {
        //并发:多线程操作同一资源类,把资源类丢入线程
        Ticket ticket = new Ticket();
        //lambda表达式  (参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"c").start();
    }
}
//资源类  oop
class Ticket{
    //属性,方法
    private int number =50;
    //买票的方式
    //synchronized 的本质:队列,锁
    public synchronized void sale(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余" +
                    number+"张票");
        }
    }
}
---------------结果---------------
A卖出了第50,剩余49张票
A卖出了第49,剩余48张票
A卖出了第48,剩余47张票
。。。
B卖出了第3,剩余2张票
A卖出了第2,剩余1张票
A卖出了第1,剩余0张票

2. Lock锁

在这里插入图片描述

lock锁中有三个接口
在这里插入图片描述

Condition 精确通知
在这里插入图片描述

标准Lock锁
在这里插入图片描述

ReadWriteLock 读写锁

在这里插入图片描述
lock锁中的两个用法:加锁/解锁
在这里插入图片描述
当我们打开ReentrantLock的源码中会发现:

默认定义了一个非公平锁
当传入一个布尔值为true则为公平锁
公平锁:非常公平,先来后到
非公平锁:可以插队(默认)
Synchronized 默认也是非公平锁

在这里插入图片描述

用Lock锁重写卖票实例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo02 {
    public static void main(String[] args) {
        //并发:多线程操作同一资源类,把资源类丢入线程
        Ticket2 ticket = new Ticket2();
        //lambda表达式  (参数)->{代码}
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"c").start();

    }
}
//资源类  oop
class Ticket2{
    //属性,方法
    private int number =50;
    //买票的方式
    Lock lock = new ReentrantLock();
    public  void sale(){
        lock.lock();  //上锁
        try {
            //业务代码
            if(number>0){
                System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余" +
                        number+"张票");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();  //解锁
        }
    }
}
---------------结果---------------
A卖出了第50,剩余49张票
B卖出了第49,剩余48张票
B卖出了第48,剩余47张票
。。。
A卖出了第2,剩余1张票
A卖出了第1,剩余0张票

Synchronized 和 Lock锁的区别

  1. Synchronized 是Java内置的关键字,Lock是一个Java类
  2. Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
  3. Synchronized 是自动的,会自动释放锁,Lock必须手动释放锁 容易发生死锁
  4. Synchronized 线程1(获得锁,阻塞) 线程2(等待,死等) ,Lock锁不一定会一直等待
  5. Synchronized 可重入锁,不可中断,非公平,Lock可重入,可以判断锁,可设置公平与否
  6. Synchronized 适合锁少量的代码同步问题,Lock锁适合锁大量的同步代码块

四. 生产者和消费者

1. Synchronized 版

/**
 * 线程之间的通信问题,生产者与消费者问题(等待唤醒,通知提醒)
 * 线程交替执行,操作同一变量,使num=0
 */
public class Demo03 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}

class Data{  //资源类  数字num
    private int num=1;
    //+1
    public synchronized void increment() throws InterruptedException {
        if (num!=0){
            //等待操作
            this.wait();
        }
        num++;
        //通知其他线程,工作完毕
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();
    }

    //-1
    public synchronized void decrement() throws InterruptedException {
        if (num==0){
            //等待操作
            this.wait();
        }
        num--;
        //通知其他线程,工作完毕
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();
    }
}
---------------结果---------------
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1
B=>0
A=>1

问题:如果线程超过两个,会有什么问题?
答:会出现虚假唤醒问题
应该将if改成while,防止虚假唤醒问题

/**
 * 线程之间的通信问题,生产者与消费者问题(等待唤醒,通知提醒)
 * 线程交替执行,操作同一变量,使num=0
 */
public class Demo03 {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}

class Data{  //资源类  数字num
    private int num=1;
    //+1
    public synchronized void increment() throws InterruptedException {
        while (num!=0){
            //等待操作
            this.wait();
        }
        num++;
        //通知其他线程,工作完毕
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();
    }

    //-1
    public synchronized void decrement() throws InterruptedException {
        while (num==0){
            //等待操作
            this.wait();
        }
        num--;
        //通知其他线程,工作完毕
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        this.notifyAll();
    }
}
---------------结果---------------
B=>0
A=>1
B=>0
C=>1
B=>0
A=>1
B=>0
C=>1
D=>0
A=>1
B=>0
C=>1
D=>0
A=>1
D=>0
C=>1
D=>0
A=>1
D=>0
C=>1

2.JUC版生产者消费者

要用Lock代替Synchronized ,就必须配套替换 wait 和 nodity
这就提到了之前的Condition,在JDK帮助文档中,明确介绍
在这里插入图片描述
代码实现:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo04 {
    public static void main(String[] args) {
        Data2 data2 = new Data2();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data2.incerment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data2.decerment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data2.incerment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    data2.decerment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
class Data2{
    private int num=1;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    public void incerment() throws InterruptedException {
        lock.lock();
        try {
            //业务代码
            while (num!=0){
                condition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void decerment() throws InterruptedException {
        lock.lock();
        try {
            while (num==0){
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"=>"+num);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
---------------结果---------------
B=>0
A=>1
B=>0
C=>1
B=>0
C=>1
B=>0
C=>1
D=>0
C=>1
D=>0
C=>1
D=>0
A=>1
D=>0
A=>1
D=>0
A=>1
B=>0
A=>1

Condition的优点:精准通知和唤醒线程

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 不同于上一个例子
 * 这次要顺序执行A B C
 */
public class Demo05 {
    public static void main(String[] args) {
        Data3 data3 = new Data3();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                data3.printA();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                data3.printB();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                data3.printC();
            }
        },"C").start();
    }
}

class Data3{
    private int num=1;  //num=1 A, 2 B,3 C
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void printA(){
        lock.lock();
        try {
            while (num!=1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>执行了PrintA");
            num=2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB(){
        lock.lock();
        try {
            while (num!=2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>执行了PrintB");
            num=3;
            condition3.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            while (num!=3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>执行了PrintC");
            num=1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
---------------结果---------------
A=>执行了PrintA
B=>执行了PrintB
C=>执行了PrintC
A=>执行了PrintA
B=>执行了PrintB
C=>执行了PrintC
A=>执行了PrintA
B=>执行了PrintB
C=>执行了PrintC
A=>执行了PrintA
B=>执行了PrintB
C=>执行了PrintC
A=>执行了PrintA
B=>执行了PrintB
C=>执行了PrintC

五. 8锁的现象

根据上面的实例,请问锁是什么,如何判断锁的是谁?

锁的内容:对象,与class模板

8锁,就是关于锁的8个问题
1、标准情况下,两个线程先打印发短信还是打电话?1/发短信2/打电话
2、 sendsms延迟4秒,两个线程先打印发短信还是打电话?1/发短信2/打电话

//问题1
//标准情况下,两个线程先打印发短信还是打电话?1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{  //线程A
            phone.sendSms();
        },"A").start();
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone.call();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
//问题2
//sendsms延迟4秒,两个线程先打印发短信还是打电话?1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{  //线程A
            phone.sendSms();
        },"A").start();
		try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone.call();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
//问题3
//新增普通线程,sendsms延迟4秒,两个线程先打印发短信还是hello?1/发短信2/hello
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{  //线程A
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone.hello();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    public void hello(){
        System.out.println("hello");
    }
}
//问题4
//两个对象,两个线程先打印发短信还是打电话 1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        //两个对象
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{  //线程A
            phone1.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone2.call();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
//问题5
//两个静态同步方法,两个线程先打印发短信还是打电话 1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{  //线程A
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone.call();
        },"B").start();
    }
}

class Phone{
    public static synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
}
//问题6
//两个对象,两个静态同步方法,两个线程先打印发短信还是打电话 1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{  //线程A
            phone1.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone2.call();
        },"B").start();
    }
}

class Phone{
    public static synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public static synchronized void call(){
        System.out.println("打电话");
    }
}
//问题7
//一个静态同步方法,一个普通同步方法,一个对象
//两个线程先打印发短信还是打电话 1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{  //线程A
            phone.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone.call();
        },"B").start();
    }
}

class Phone{
    public static synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
//问题8
//一个静态同步方法,一个普通同步方法,两个对象
//两个线程先打印发短信还是打电话 1/发短信2/打电话
import java.util.concurrent.TimeUnit;

public class Demo06 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(()->{  //线程A
            phone1.sendSms();
        },"A").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{   //线程B
            phone2.call();
        },"B").start();
    }
}

class Phone{
    public static synchronized void sendSms(){
        //捕获异常
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

答案:
1、发短信 打电话
2、发短信 打电话
原因:synchronized锁的对象是方法的调用者!
两个方法用的是同一个锁(phone),谁先拿到锁谁先执行
3、hello 发短信
hello没有锁,不是同步方法,不受锁的影响
4、打电话 发短信
两个对象,两个调用者,两个锁,没有冲突
5、发短信 打电话
Phone是唯一的一个CLass对象,类一加载就有了,锁的是Class
6、发短信 打电话
两个对象的Class类模板只有一个,锁的是Class
7、打电话 发短信
8、打电话 发短信
两个锁 锁的内容不一样,没有冲突

六. 集合类不安全

1.List不安全

实例一:

//安全线程实例
import java.util.Arrays;
import java.util.List;

public class ListTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("1", "2", "3", "4");
        list.forEach(System.out::println);
    }
}
结果:
1
2
3
4
//不安全实例,及解决方案
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

//java.util.ConcurrentModificationException  并发修改异常
public class ListTest {
    public static void main(String[] args) {
        //并发下,arraylist是不安全的
        /*
            解决方案:
            1.将List<Object> list = new ArrayList<>();
            修改为:List<Object> list = new Vector<>();
            2.将List<Object> list = new ArrayList<>();
            修改为:List<Object> list = Collections.synchronizedList(new ArrayList<>());
            3.将List<Object> list = new ArrayList<>();
            修改为:List<Object> list = new CopyOnWriteArrayList<>();
         */
        //CopyOnWrite 写入时复制 ,简称COW ,是计算机程序设计领域的一种优化策略
        //多个线程调用的时候,资源在读取的时候是一个固定的,但是写入的时候,可能会出现覆盖操作
        //相当于在写入的时候避免覆盖造成数据问题
        //后面会讲 mycat
        List<Object> list = new ArrayList<>();
        for (int i = 1; i < 11; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,10));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}
//注:JDK11 后将 COW(CopyOnWrite)修改为了synchronized

2.Set不安全

//Set 同理
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

//同样出现了java.util.ConcurrentModificationException  并发修改异常
public class SetTest {
    public static void main(String[] args) {
        /*
        解决方法:
        1.Set<String> set = new HashSet<>();
        修改为:Set<String> set = Collections.synchronizedSet(new HashSet<>());
        2.Set<String> set = new HashSet<>();
        修改为:Set<String> set = new CopyOnWriteArraySet<>();
         */
        Set<String> set = new HashSet<>();
        for (int i = 1; i < 10; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

HashSet的本质是什么

public HashSet() {
	 map = new HashMap<>();
}

add set本质就是 map ,key是无法重复的

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

在这里插入图片描述

Map不安全

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class MapTest {
    public static void main(String[] args) {
        //map是这样用的吗,默认等价于什么
        //不是,默认等价于new HashMap<>(16,0.75);
        //加载因子,初始化容量
        //方法一:Map<String, Object> map = Collections.synchronizedMap(new HashMap<>());
        //方法二:Map<String, Object> map = new ConcurrentHashMap<>();
        Map<String, Object> map = new HashMap<>();
        for (int i=1;i<11;i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

ConcurrentHashMap的原理:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值