
并发编程会引发哪些问题,如何解决?
1.上下文切换,
解决方案:1.使用java的atomic包的原子 *** 作类进行 *** 作,该 *** 作基于CAS算法,减少加锁。
2.无锁并发 不同线程处理不同分段的数据
3.减少不必要的线程
4.协程,单线程里多任务调度
2.死锁
解决方案:一个线程避免获取多个锁
避免一个线程在一个锁内获取多个资源
使用定时锁 lock.tryLock(timeout )
3.资源限制
解决方案:使用集群并发执行程序
并发机制的实现方式和原理
1.volatile 对有volatile修饰的变量进行 *** 作的代码被编译成字节码时会在后面增加一条 lock addl指令,lock指令会将缓存数据回写内存,其他线程中该变量的缓存数据失效,保证volatile变量的可见性。addl指令会插入一条内存屏障,防止指令重排序,保证有序性。
2.synchronized 以代码块同步为例,synchronized修饰的代码块被编译成字节码时会在前后插入一条monitorenter和monitorexit指令,这两条指令分别对应着java内存模型的lock和unlock *** 作,由java内存模型 *** 作的释义可以看出synchronized保证了线程安全的原子性、有序性、可见性。
3.Lock 显式的获取锁和释放锁
与synchronized区别:1.提供了lockInterruptly()方法,可被中断地获取锁
2.可以设置多个获取锁的条件
3.公平锁 最先申请获取锁的线程在锁被释放后先获得锁
ConcurrentHashMap实现原理
通过锁分段技术解决HashMap线程不安全和HashTable同步锁 *** 作效率低下的问题,给每段数据配一个锁,当一个线程锁定一段数据时,其他线程可以访问其他分段的数据。
它由Segment数组和HashEntry数组构成,Segment是一种ReentrantLock,每个Segment守护着一组HashEntry数组,当对HashEntry中的数据进行 *** 作时必须先获得它的Segment可重入锁。
ConcurrentlinkedQueue
它是一个非阻塞队列,由一个head节点和tail节点组成,每个节点由一个节点元素和指向下一节点的引用next组成,从而组成一张链表结构的队列
它的入队和出队 *** 作使用CAS算法保证线程安全
阻塞队列
当队列满时,向队列插入元素的线程会被阻塞直至队列不满
当队列为空时,从队列获取元素的线程会被阻塞直至队列非空
常用于生产消费场景
java阻塞队列:
ArrayBlockingQueue
linkedBlockingQueue
使用通知的方式实现 通过Condition的await()和signal()方法实现
原子 *** 作类 使用CAS算法 *** 作数值 将预期值与原始值相比较 如果相同则用新值更新原始值,如果不同则循环进行conpareAndSet *** 作
原子更新基本数据类型 AtomicInteger
原子更新数组 AtomicIntegerArray
原子更新引用 AtomicReference
原子更新字段 AtomicIntegerFieldUpdater
java中的并发工具类
等待多线程完成的CountDownLatch
构造一个CountDownLatch对象,构造对参为并发执行的任务数
调用CountDownLatch的await方法阻塞当前线程,知道所有任务完成或者超过等待时间
CyclicBarrier 同步屏障 让一组线程到达一个屏障时被阻塞知道所有线程到达,可用于多线程计算最后合并结果的场景
CountDownLatch只能使用一次,CyclicBarrier可以通过reset方法重置计数器
cyclicBarrier.await()阻塞当前线程直至所有线程到达屏障
Semaphore 控制并发线程数 semaphore.accuire()获取许可证 semaphore.release() 归还许可证
Exchanger 线程数据交换 当一个线程调用exchange()方法,需要等待另一个线程执行exchange()方法 可用于数据校对
java中的线程池
线程池的实现原理:
当一个任务提交到线程池时
1.判断核心线程池是否已满,如果不是,则创建一个新的线程执行任务,否则进入下一流程
2.判断任务队列是否已满 ,如果不满则把当前任务加入任务队列,否则进入下一流程
3.判断线程池是否已满,如果不是,则创建一个线程来执行任务,否则将任务交给饱和策略
通过ThreadPoolExecutor创建线程池,指定
核心线程数量corePoolSize、
阻塞队列(用于存放任务)runnableTaskQueue、
线程池最大数量maximumPoolSize、
创建线程的工厂ThreadFactory、
饱和策略RejectedExcutionHandler、
线程空闲后存活的时间keepAliveTime
通过execute()方法(没有返回值)和submit()方法(有返回值)向线程池提交任务
通过shutdown或shutdownNow方法调用所有线程的interrupt方法来终端线程关闭线程池
CPU密集型配置尽可能小的线程池,N(cpu数量)+1个线程
IO密集型配置尽可能多的线程的线程池,2*cpu数量个线程
任务优先级不同的任务可以使用任务优先级队列PriorityBlockingQueue来让优先级高的任务优先执行,通过实现copareto方法或者自定义Comparetor来进行优先级排序
Executor框架
任务 Runnable Callable
任务的执行 Executor <-ExcutorService <-ThreadPoolExecutor和ScheduledThreadPoolExecutor
异步任务结果 Future和FutureTask
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)