Java-线程池 原子性 类
线程池
构造方法
调用Executors静态方法创建
创建一个默认无限大小的线程池(最大不超过int的范围):
static ExecutorService newCachedThreadPool()
例:ExecutorService es = Executors.newCachedThreadPool();
创建一个指定大小最多线程数量的线程池:
static newFixedThreadPool(int nThreads)
例:ExecutorService es = Executors.newCachedThreadPool();
调用方法
Future<?> submit(Runnable task) // 提交一个 Runnable 任务用于执行,()里可以传一个λ表达式,也可以传实现Runnable对象
void shutdown 关闭线程池
使用Executors中所提供的静态方法来创建
直接创建线程池对象
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
参数一:核心线程数量 --------------> 核心线程数量 (不能小于0)
参数二:最大线程数 --------------> 线程池中最大线程的数量 (不能小于等于0,最大数量 >= 核心线程数量)
参数三:空闲线程最大存活时间 --------------> 空闲时间(值) (不能小于0)
参数四:时间单位 --------------> 空闲时间(单位) (时间单位)
(秒:TimeUnit.SECONDS 分:TimeUnit.MINUTES 时:TimeUnit.HOURS ...)
参数五:任务队列 --------------> 阻塞队列 (不能为null)
(new ArrayBlockingQueue<>(int capacity)) //任务队列
参数六:创建线程工厂 --------------> 创建线程的方式 (不能为null)
(Executors.defaultThreadFactory())
参数七:任务的拒绝策略 --------------> 要执行的任务过多时的解决方案 (不能为null)
(new ThreadPoolExecutor.AbortPolicy())
任务的拒绝策略
ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。--是默认的策略。
ThreadPoolExecutor.DiscardPolicy: 丢弃任务,但是不抛出异常 这是不推荐的做法。
ThreadPoolExecutor.DiscardOldestPolicy: 抛弃队列中等待最久的任务 然后把当前任务加入队列中。
ThreadPoolExecutor.CallerRunsPolicy: 调用任务的run()方法绕过线程池直接执行。
原子性
volatile-问题
出现原因:
当A线程修改了共享数据时,B线程没有及时获取到最新的值,如果还在使用原先的值,就会出现问题
1 ,堆内存是唯一的,每一个线程都有自己的线程栈。
2 ,每一个线程在使用堆里面变量的时候,都会先拷贝一份到变量的副本中。
3 ,在线程中,每一次使用是从变量的副本中获取的。
volatile解决
Volatile关键字 :强制线程每次在使用的时候,都会看一下共享区域最新的值
例: public static volatile int money = 1000; //每个线程使用前都会重新获取此值
原子性
所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,是一个不可分割的整体
AtomicInteger的常用方法
public AtomicInteger() //初始化一个默认值为0的原子型Integer
public AtomicInteger(int initialValue) //初始化一个指定值的原子型Integer
AtomicBoolean: 原子更新布尔类型 //与AtomicInteger相似
AtomicLong: 原子更新长整型 //与AtomicInteger相似
int get(): //获取值
int getAndIncrement(): //以原子方式将当前值加1,注意,这里返回的是自增前的值。
int incrementAndGet(): //以原子方式将当前值加1,注意,这里返回的是自增后的值。
int addAndGet(int data): //以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。
int getAndSet(int value): //以原子方式设置为newValue的值,并返回旧值。
悲观锁和乐观锁
synchronized(悲)和CAS(乐)的区别
相同点:在多线程情况下,都可以保证共享数据的安全性。
不同点:synchronized总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每次操作共享数据之前,都会上锁。(悲观锁)
cas是从乐观的角度出发,假设每次获取数据别人都不会修改,所以不会上锁。只不过在修改共享数据的时候,会检查一下,别人有没有修改过这个数据。
如果别人修改过,那么我再次获取现在最新的值。
如果别人没有修改过,那么我现在直接修改共享数据的值.(乐观锁)
乐观锁:
1: 只针对 值的修改 只在修改处 加校验。 具体大段的逻辑 他不管。
2: 针对 多查 少改。
悲观锁(synchronized)
1: 针对 大段的逻辑 上下文关联的
并发工具类
Hashtable集合
HashMap 线程不安全的 效率比较高。 开发中在局部位置定义双列集合,首选HashMap,因为局部位置不涉及共享数据 ,属于单线程开发,使用HashMap效率最高。
Hashtable 每个方法都是 同步方法,用synchronized修饰 。 效率比较低
ConcurrentHashMap
线程安全 效率较高
原理:
jdk1.7之前原理:
使用的 哈希表的嵌套, 并使用悲观锁synchronized对 小哈希表进行局部锁定,所以他可以同时使用16条线程共同操作此集合。
jdk1.8之后的原理:
对横向的数组数据 使用乐观锁cas
对竖向的链表和红黑树 使用悲观锁synchronized 锁对象是红黑树或者链表的头结点。
CountDownLatch
可以设置 某一线程 等待其他几条线程结束之后 再开始执行
方法
构造方法:
public CountDownLatch(int count) 参数传递线程数,表示等待线程数量
成员方法:
public void await() 让线程等待
public void countDown() 当前线程执行完毕
Semaphore
限制同一时间线程执行的个数,可以控制访问特定资源的线程数量。
方法:
构造方法:
public Semaphore(int count) // 参数传递可执行的线程数量
方法:
public void acquire() //从此信号量获取一个许可,在提供一个许可前一直将线程阻塞
public void release() //释放一个许可,将其返回给信号量。