0
点赞
收藏
分享

微信扫一扫

03-关系和非关系型数据库对比

彩虹_bd07 2023-11-16 阅读 37

Callable接口

Callable是一个interface,相当于给线程封装了一个返回值,方便程序猿借助多线程的方式计算结果.

代码示例: 使用 Callable 版本,创建线程计算 1 + 2 + 3 + ... + 1000,

在上面代码中,get()方法会抛出异常.

理解Callable

Callable Runnable 相对 , 都是描述一个 " 任务 ". Callable 描述的是带有返回值的任务 , Runnable 描述的是不带返回值的任务 .

Callable 通常需要搭配 FutureTask 来使用 . FutureTask 用来保存 Callable 的返回结果 . 因为Callable 往往是在另一个线程中执行的 , 啥时候执行完并不确定 .

FutureTask 就可以负责这个等待结果出来的工作 .

ReentrantLock类

可重入互斥锁 . synchronized 定位类似 , 都是用来实现互斥效果 , 保证线程安全 .

ReentrantLock的用法

​​​​​​​

 

ReentrantLock和Synchronized的区别

1. Synchronized是非公平锁,ReentrantLock默认是非公平锁,但可以通过一个构造方法传入true开启公平锁模式

2. Synchronized不需要手动释放锁,而ReentrantLock需要手动释放锁.

3. Synchronized提供的加锁操作就是 死等.只要获取不到锁,就会一直阻塞等待.而ReentrantLock提供了更灵活的等待方式.

4. ReentrantLock提供了更强大,更方便的的等待通知机制.

Synchronized搭配的是wait notify,notify的时候是随机唤醒一个等待线程,而ReentrantLock搭配的是Condition类,进行唤醒的时候可以唤醒指定线程. 

5. ReentrantLock t通常搭配 try catch 使用.

信号量 Semaphore

信号量, 用来表示 "可用资源的个数". 本质上就是一个计数器.

理解信号量

Semaphore PV 操作中的加减计数器操作都是原子的 , 可以在多线程环境下直接使用 .

CountDownLatch

CountDownLatch的主要任务是等待N个任务执行结束

1. 构造CountDownLatch实例,初始化10代表有10个任务要完成.

​​​​​​​

2.每执行完一个任务,都会调用 count.countDown()方法,每调用一次, CountDownLatch内部的计数器就会减1.

3. 当主线程中使用 latch.await(); 阻塞等待所有任务执行完毕. 相当于计数器为 0 了.

多线程使用哈希表

在之前数据结构学习了哈希表,其中HashMap是线程不安全的,HashTable是线程安全的, 而这里主要讲的是ConcurrentHashMap,是一种更优化的线程安全哈希表.

​​​​​​​

Synchronized加锁是多个线程针对同一个对象加锁,就会产生锁竞争,一个HashTable只有一把锁,此时两个线程在访问哈希表中的任意元素的时候都会发生锁竞争.

1. ConcurrentHashMap任然是用synchronized进行加锁,但不是整个锁对象,而是链表的头节点作为所对象,大大降低了锁冲突的概率

2. ConcurrentHashMap针对读操作不加锁,但使用volatile保证从内存读取元素时原子的,而只针对写操作进行加锁.

3. ConcurrentHashMap内部充分利用了CAS,进一步削减加锁操作的数目.

4. 针对扩容采取了化整为零的方式.

    HashTable/HashMap扩容:创建一个更大的数组,把旧的数组上的链表上的每个元素都搬入到新的数组,相当于删除原来数组在重新插入到新的数组上.这个扩容会在某次put时进行出发,当数据太多,就会导致这种扩容会比较耗时

     ConcurrentHashMap中,扩容的方式是每次搬运一小部分元素,创建新的数组,旧的数组保留,每次put操作,都忘新数组上添加,同时进行一部分搬运,每次get的时候,旧的数组和新的数组都查询,每次remove只要找到元素删除即可.经过一定时间,所有的元素都搬运完了,最终在释放旧数组.

举报

相关推荐

0 条评论