java并发编程
2021/7/4 14:24:27
本文主要是介绍java并发编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
系列文章目录
文章目录
- 系列文章目录
- 前言
- 一、Java 的5个状态 ?
- 二、volatile
- 三、CAS
- 缺点: 自旋 极端情况 循环比较 开销大 cpu 耗损
- ABA问题
- List 集合
- 线程池
前言
ConcurrentModificationException
StackOverflowError
OutOfMemoryError
RejectedExecutionException
一、Java 的5个状态 ?
1 新建(new)
2 运行(Runable)
3 无限期等待(Waiting)
1.没有设置 Timeout 参数的 Object.wait() 方法。
2.没有设置 Timeout 参数的 Thread.join() 方法。
4 限期等待(Timed Waiting)
1.Thread.sleep() 方法。
2.设置了 Timeout 参数的 Object.wait() 方法。
3.设置了 Timeout 参数的 Thread.join() 方法。
5 阻塞(Blocked)
二、volatile
1、volatile java 虚拟机提供的轻量级同步机制
(1),内存可见
(2),禁止指令重排
(3),不保证原子性
三、CAS
CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CASI汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
缺点: 自旋 极端情况 循环比较 开销大 cpu 耗损
ABA问题
CAS会导致“ABA问题”。
CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。
比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功。
尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。
List 集合
不安全 :【数组】 ArrayList
安全:【数组】CopyOnWriteArrayList 、Collections.synchronizedList(new ArrayList<>());
不安全:【链表】LinkedList
不安全:【HashMap】HashSet 初始值16 加载因子0.75
读写锁例子:
package com.yang.yimall.order.jmm.list; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 多个线程同时获取一个资源没问题 * <p> * 写 只能 一个线程来写 */ public class ReadAndWriteLock { /** * 读 - 读 可以 * 读 - 写 不可以 * 写 - 写 不可以 */ public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i < 5; i++) { final int temp = i; new Thread(() -> { myCache.put(temp + "", temp); }).start(); } for (int i = 0; i < 5; i++) { final int temp = i; new Thread(() -> { myCache.get(temp + ""); }).start(); } } } class MyCache { Map<String, Object> map = new HashMap<>(); static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); void put(String key, Object value) { lock.writeLock().lock(); map.put(key, value); try { System.out.println(Thread.currentThread().getName() + "正在写入....."); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "正在写入完成"); } catch (Exception e) { } finally { lock.writeLock().unlock(); } } void get(String key) { lock.readLock().lock(); map.get(key); try { System.out.println(Thread.currentThread().getName() + "正在读取....."); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "正在读取完成"); } catch (Exception e) { } finally { lock.readLock().lock(); } } }
线程池
/** * 线程池的 7 大参数 * <p> * corePoolSize 核心线程数:创建好以后准备就绪的线程数量,就等来执行异步任务 ,即使空闲时候也存在 除非设置超时时间 * maximumPoolSize 最大数量:控制数量 * keepAliveTime 存活时间 : maximumPoolSize-corePoolSize 的这部分线程使用后 销毁之前等待下一次消费的时间, * TimeUnit 时间单位 * BlockingQueue<Runnable> workQueue, 阻塞队列 : n-maximumPoolSize 剩下的任务放在队列里面 ,只要有空闲线程 就回去队列里面拿取任务 * threadFactory : 创建刚工厂 可以默认 * handler : 如果队列满了的按照指定策略处理 */ // threadFactory 策略: // AbortPolicy 默认 直接报异常 RejectedExecutionException // CallerRunsPolicy 谁调用给谁 // DiscardOldestPolicy 丢弃等待最久的 // DiscardPolicy 直接丢弃
/** * 工作顺序 * 1.1 线程池创建,准备好核心数量线程,准备接受任务 * 1.2 core 满了,就将进来的任务放在阻塞队列里面, 空闲的核心就会 自己去阻塞队列里面获取,执行任务 * 1.3 阻塞队列满了 就直接开启新线程, 只能开到max指定数量 * 1.4 m如果max满了 执行指定拒绝策略 * 1.5 如果max 执行完成有空闲 在指定 keepAliveTime 以后释放 maximumPoolSize-corePoolSize 线程 public static ExecutorService threadExecutor = new ThreadPoolExecutor( 5, 200, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); */
这篇关于java并发编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南