1. List集合线程安全

  • CopyOnWriteArrayList是线程安全的集合;
  • ArrayList是线程不安全的集合;
  • Vector是线程安全的集合(不推荐使用)

1.1 解决ArrarList线程不安全的方案:

  • 使用Vector
    查看Vector的add()方法,发现相比于ArrayList的add()方法前面加了synchronized修饰,因此是线程安全的
  • 使用Collectiobns.synchronizedlist(new ArrayList< String >):
    Collections集合工具类提供一系列线程安全的集合构造方法。
  • 使用 JUC包下的CopyOnWriteArrayList集合:
    一种线程安全的集合,CopyOnWrite的意思是写入时复制,是一种计算机程序设计优化策略,解决多线程写入覆盖问题。

1.2 CopyOnWriteArrayList的add方法源码:

/*** Appends the specified element to the end of this list.** @param e element to be appended to this list* @return {@code true} (as specified by {@link Collection#add})*/public boolean add(E e) {final ReentrantLock lock = this.lock;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();}}

CopyOnWriteArrayList的核心是 读写分离 Object[] newElements = Arrays.copyOf(elements, len + 1);通过复制之前的数组,并长度加一,添加加入的值,从而实现add方法。

2.Set集合线程安全

2.1 HashSet是线程不安全的,解决方案有两种:

  • Collections.synchronizedSet():
    Set set = Collections.synchronizedSet(new HashSet<>());
  • CopyOnWriteArraySet:
    Set set = new CopyOnWriteArraySet<>();

2.2HashSet的底层是什么?

/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/public HashSet() {map = new HashMap<>();}

从源码中可以看出HashSet底层就是HashMap。

/*** Adds the specified element to this set if it is not already present.* More formally, adds the specified element <tt>e</tt> to this set if* this set contains no element <tt>e2</tt> such that* <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.* If this set already contains the element, the call leaves the set* unchanged and returns <tt>false</tt>.** @param e element to be added to this set* @return <tt>true</tt> if this set did not already contain the specified* element*/public boolean add(E e) {return map.put(e, PRESENT)==null;}

HashSet中add()方法,调用的还是HashMap的底层put()方法。

3.Map集合线程安全(重点)

HashMap源码分析:跳转链接
ConcurrentHashMap源码分析:链接跳转

4.Callable创建线程

对比Runnable,可以有返回值、有参数
使用步骤:资源类实现Callable接口,重写 T call() 方法,创建资源类实例mt ,然后new Thread(new FutureTask(mt)) .start()开启一个线程

public class Demo1_Callable {public static void main(String[] args) throws InterruptedException, ExecutionException {/*** 开启线程需要 中间类 FutureTask 类* 该类的·构造函数 可以 将 Callable 实例绑定,并且 该类实现 Runnable 接口*/MyThread mt = new MyThread();//1.for (int i = 0; i < 10; i++) {FutureTask target = new FutureTask(mt);//2.new Thread(target).start();//3.// 返回值System.out.println(target.get()); // 这个get方法可能会产生阻塞}}
}class MyThread implements Callable<String> {Lock lock = new ReentrantLock();@Overridepublic String call() {//lock.lock();try {System.out.println(Thread.currentThread().getName() + "====> test" );return "带返回值的Callable接口";// 唤醒//Condition condition = lock.newCondition();//condition.signal();} catch (Exception e) {e.printStackTrace();return null;} finally {//lock.unlock();}}
}

5、三大辅助工具类

5.1 CountDownLatch减法计数器类

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

栗子:

public class Demo1_CountDownLatch {public static void main(String[] args) throws InterruptedException {// 创建计数器类CountDownLatch countDownLatch = new CountDownLatch(5);for (int i = 0; i < 5; i++) {new Thread(()-> {System.out.println(Thread.currentThread().getName() +"===>执行完毕");countDownLatch.countDown();//数量减1},String.valueOf(i)).start();}// 等待上面线程全部执行完毕,才执行性下面代码countDownLatch.await();System.out.println("结束执行");}
}输出:
1===>执行完毕
4===>执行完毕
2===>执行完毕
3===>执行完毕
0===>执行完毕
结束执行

API

  • countDownLatch.countDown() :数量减1
  • countDownLatch.await():等待计数器归0,然后在向下执行。

CountDownLatch底层原理

CountDownLatch通过AQS(AbstractQueuedSynchronizer)里面的共享锁来实现的。
ReentrantLock也是使用AQS

5.3 CyclicBarrier加法计数器类 [ˈsaɪklɪk] [ˈbæriər]

达到指定目标个数线程执行完毕,才执行绑定的任务,否则会阻塞

public static void main(String[] args)  {CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{System.out.println("6个线程全部执行完才输出!");});for (int i = 1; i <= 10; i++) {final int temp = i;new Thread(()->{System.out.println(Thread.currentThread().getName() + "---执行完毕--");try {// 等待设置目标线程数达标,执行绑定的方法cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}},String.valueOf(temp)).start();}
}
输出结果:
2===>执行完毕~~
1===>执行完毕~~
3===>执行完毕~~
5===>执行完毕~~
4===>执行完毕~~
6===>执行完毕~~
6个线程全部执行完才输出!!
7===>执行完毕~~
8===>执行完毕~~
9===>执行完毕~~
10===>执行完毕~~此时程序还未停止

5.4 Semaphore计数信号量

概念

  • 一个计数信号量。 在概念上,信号量维持一组许可证。
  • 如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。
  • 每个release()添加许可证,潜在地释放阻塞获取方。
  • Semaphore保留可用数量的计数,并相应地执行。
  • 假如只有3个停车位,6辆车,无空车位之前其他三辆车需要等待
public static void main(String[] args)  {// 可以理解为只有3个车位Semaphore semaphore = new Semaphore(3);for (int i = 1; i <= 8; i++) {new Thread(()->{try {// 占位semaphore.acquire();System.out.println(Thread.currentThread().getName() + "===>拿到了车位!");// 停车时间TimeUnit.SECONDS.sleep(3);// 离开车位System.out.println(Thread.currentThread().getName() + "====>离开了!");} catch (InterruptedException e) {e.printStackTrace();}finally {// 最后告诉等待的人有1个空位了semaphore.release();}},String.valueOf(i)).start();}
}
输出结果:
2===>拿到了车位!
3===>拿到了车位!
1===>拿到了车位!
1====>离开了!
3====>离开了!
2====>离开了!
5===>拿到了车位!
6===>拿到了车位!
4===>拿到了车位!
5====>离开了!
4====>离开了!
6====>离开了!
7===>拿到了车位!
8===>拿到了车位!
7====>离开了!
8====>离开了!

API

  • semaphore.acquire():获得资源,如果资源已经没了,等待被释放为止
  • semaphore.release():释放资源,资源量加1,唤醒等待的线程

JUC(3)List、Set、Map集合线程安全Callable创建线程三大工具类:CountDownLatch减法计数器、CyclicBarrier加法计数器、Semaphore计数信号量相关推荐

  1. 集合之Map家族的TreeMap + Sort +Properties及Collections工具类和总结

    集合之Map家族的TreeMap + Sort +Properties及Collections工具类和总结 一.TreeMap 1.TreeMap的使用 import java.util.Arrays ...

  2. day14 线程池、原子性、并发工具类

    目录 一.线程池 1.1 线程状态 1.2 线程池的基本原理 1.3 Executors默认线程池 1.4 创建指定上限的线程池 1.5 ThreadPoolExecutor(线程池执行器) 1.5. ...

  3. 线程了解以及创建线程的Threading模块中的部分方法

    了解线程 1.什么是线程 在传统的操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程,其实就是一条流水线的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源 ...

  4. Java—遍历集合的N种方式总结Collections工具类

    遍历集合的N种方式总结 [示例1]遍历List方法1,使用普通for循环 for(int i=0;i<list.size();i++){         //list为集合的对象名 String ...

  5. Java JUC工具类--CountDownLatch

    CountDownLatch:用于监听某些初始化操作,并且线程进行阻塞,等初始化执行完毕后,通知主线程继续工作执行 package com.example.core.juc;import java.u ...

  6. java 创建线程_java多线程|创建线程的各种方式

    javaDEMO 本网站记录了最全的各种JavaDEMO ,保证下载,复制就是可用的,包括基础的, 集合的, spring的, Mybatis的等等各种,助力你从菜鸟到大牛,记得收藏哦~~https: ...

  7. JAVA线程并发数量控制_Java并发工具类(三):控制并发线程数的Semaphore

    作用 Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 简介 Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数 ...

  8. 多线程(一) 线程概念及创建线程的方法

    多线程(一) 多线程基础 前言 我只是一个新上路的小菜鸟,通过分享自己的所学来巩固知识,文中如有错误希望能够指出改正. 一.线程的相关概念 程序 程序是为了完成特定任务,用某种语言编写的一组指令的集合 ...

  9. 陈硕智能指针线程安全_C++ 创建线程的方法

    C++开发过程中,创建线程是必不可少的,今天就给大家说说c++创建线程的方法,主要介绍我常用的2种方法. 第一种:CreateThread HANDLE WINAPI CreateThread( t ...

最新文章

  1. 预测人民币在2006年最终的收盘价
  2. 自定义ViewGroup实现ViewPager的滑动效果
  3. 计算机没有autoCAD_挑战在一年内用晚上业余时间学会灵活运用CAD(1)|cad|autocad|图学|计算机|电子电路...
  4. ArcGIS中生成蜂窝多边形算法解析
  5. 单片机c语言程序设计叶俊明,单片机C语言程序设计
  6. windows修改远程桌面RDP连接数
  7. socket阻塞与非阻塞,同步与异步
  8. SkyEye——汽车电子系统仿真测试工具
  9. python效率低为什么_为什么 Python 这么慢?
  10. libsvm2.89在matlab,libsvm-mat-2.89-3工具箱,方便实用
  11. 【转载】VC遍历文件夹下所有文件和文件夹
  12. 许久未见,归来仍是少年?
  13. cyclone小知识(二)——cyclone加载扫描工程的数据
  14. 萤火虫小巷2(看完了)
  15. 登陆远程kvm_KVM远程VMM管理
  16. SCI 投稿全过程信件模板一览
  17. 初识动态规划(一)简单入门动态规划与上手操作
  18. 上证指数(000001)股票历史数据,下载上证指数(000001历史数据
  19. Ubuntu系统界面启动后启动开机自启动后锁屏
  20. 堪称神级的Java技术栈手册火了!

热门文章

  1. PTA 7-33 统计素数并求和
  2. 去掉CodeGear的Welcome page.
  3. 计算机组成原理,计算机系统总线,总线分类、特性、性能指标、结构以及总线控制,判优控制通信控制
  4. Windows 11 正式版最低配置要求来了,你的电脑支持吗?
  5. ComponentOne Studio Enterprise 2022
  6. 多普达各种机型硬启方法大全(包含谷歌系统机型)
  7. 详解开发、实施、运维的区别
  8. 拯救十年前的利盟z25打印机
  9. 开发游戏音频程序——MP3的播放
  10. Jmeter书中不会教你的(68)——jdbc request详解