JavaEE-HashTable、HashMap、ConcurrentHashMap 之间的区别

HashMap是非线程安全的高效数据结构,允许键值为null且使用数组+链表+红黑树实现。HashTable则是线程安全但效率低,全局只有一把锁。ConcurrentHashMap是线程安全的优化版,使用分段锁降低冲突,支持并发读写,提供更好的性能。
摘要由CSDN通过智能技术生成

HashTable, HashMap, ConcurrentHashMap都是Map接口的实现类,都是以key-value的形式来存储数据

HashMap

  1. HashMap 的键值可以为null (当key为空时,哈希会被赋值为0)
  2. HashMap 的默认初始容量是16, 最大容量是2^30
  3. HashMap 使用的数据结构是 数组 + 链表 + 红黑树
    如果链表中结点个数 > 8时,链表 将转化为 红黑树
    如果链表中结点个数 < 6时,红黑树 又转化为 链表
    如果哈希桶中某条链表的个数 > 8时,并且桶的个数超过64时,才会将链表转换为红黑树。否则就直接扩容
  4. HashMap 效率非常高,但线程不安全

HashTable

  1. HashTable 的键值不能为null
  2. HashTable 虽然线程安全,但只是简单得用 synchronized 给所有方法加锁,相当于是对this加锁,也就是对整个HashTable对象进行加锁(非常无脑)
    一个HashTable对象只有一把锁,如果两个线程访问同一个对象时,就会发生锁冲突
  3. HashTable效率非常低,因为无脑加锁原因,比如一些读操作不存在线程不安全问题,所以这样的加锁方式导致效率非常低
    比如 某个线程触发了扩容机制,那就会由这个线程完成整个扩容过程,如果元素特别多的情况下,效率非常低,其他线程阻塞等待的时间会特别长
  4. HashTable 使用的数据结构是 数组 + 链表

ConcurrentHashMap

  1. ConcurrentHashMap 的键值不可以为null
  2. ConcurrentHashMap 使用的数据结构是 数组 + 链表 + 红黑树
  3. ConcurrentHashMap 最重要的点要说 线程安全,ConcurrentHashMap 相比比较于HashTable 有很多的优化,最核心的思路就是:降低锁冲突的概率
  • 锁粒度的控制
    ConcurrentHashMap 不是锁整个对象,而是使用多把锁,对每个哈希桶(链表)都进行加锁,只有当两个线程同时访问同一个哈希桶时,才会产生锁冲突,这样也就降低了锁冲突的概率,性能也就提高了
    
  • ConcurrentHashMap 只给写操作加锁,读操作没加锁
    如果两个线程同时修改,才会有锁冲突
    如果两个线程同时读,就不会有锁冲突
    如果一个线程读,一个线程写,也是不会有锁冲突的
    (这个操作也是可能会锁冲突的,因为有可能,读的结果是一个修改了一半的数据
    不过ConcurrentHashMap在设计时,就考虑到这一点,就能够保证读出来的一定时一个“完整的数据”,要么是旧版本数据,要么是新版本数据,不会是读到改了一半的数据;而且读操作中也使用到了volatile保证读到的数据是最新的)
    
  • 充分利用到了CAS的特性
    比如更新元素个数,都是通过CAS来实现的,而不是加锁
    
  • ConcurrentHashMap 对于扩容操作,进行了特殊优化
    HashTable的扩容是这样:当put元素的时候,发现当前的负载因子已经超过阀值了,就触发扩容。
    扩容操作时这样:申请一个更大的数组,然后把这之前旧的数据给搬运到新的数组上
    但这样的操作会存在这样的问题:如果元素个数特别多,那么搬运的操作就会开销很大
    执行一个put操作,正常一个put会瞬间完成O(1)
    但是触发扩容的这一下put,可能就会卡很久(正常情况下服务器都没问题,但也有极小概率会发生请求超时(put卡了,导致请求超时),虽然是极小概率,但是在大量数据下,就不是小问题了)
    ConcurrentHashMap 在扩容时,就不再是直接一次性完成搬运了
    而是搬运一点,具体是这样的
    扩容过程中,旧的和新的会同时存在一段时间,每次进行哈希表的操作,都会把旧的内存上的元素搬运一部分到新的空间上,直到最终搬运完成,就释放旧的空间
    在这个过程中如果要查询元素,旧的和新的一起查询;如果要插入元素,直接在新的上插入;如果是要删除元素,那就直接删就可以了
    
JavaEE-图书管理系统通常需要包含以下数据库表: 1. 用户表(user):包括用户ID、用户名、密码、邮箱等字段。 2. 图书表(book):包括图书ID、图书名称、作者、出版社、ISBN号等字段。 3. 借阅记录表(borrow_record):包括借阅记录ID、用户ID、图书ID、借阅时间、归还时间等字段。 4. 管理员表(admin):包括管理员ID、管理员名称、密码等字段。 以下是JavaEE-图书管理系统数据库代码示例: ```sql -- 用户表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, `email` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 图书表 CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `author` varchar(50) NOT NULL, `publisher` varchar(50) NOT NULL, `isbn` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 借阅记录表 CREATE TABLE `borrow_record` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `book_id` int(11) NOT NULL, `borrow_time` datetime NOT NULL, `return_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_user_id_idx` (`user_id`), KEY `fk_book_id_idx` (`book_id`), CONSTRAINT `fk_book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 管理员表 CREATE TABLE `admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` -- 相关问题--: 1. 如何创建数据库表? 2. 如何在JavaEE中连接数据库? 3. 数据库中的什么是外键?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼王胖嘟嘟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值