hashMap,linkedHashMap以及synchronized和lock的一点总结

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
存储位置 = f(关键字)
这个函数f一般称为哈希函数。
在哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1)。
哈希表的主干就是数组。
当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突。
数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。
而HashMap即是采用了链地址法,也就是数组+链表的方式解决哈希冲突。
重写equals时也要同时覆盖hashcode,保证在equals相同的情况下hashcode值必定相同,如果重写了equals而未重写hashcode方法,可能就会出现两个没有关系的对象equals相同的(因为equal都是根据对象的特征进行重写的),但hashcode确实不相同的。


LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序。


TreeMap 可以用于排序。


HashTable因为内部是采用synchronized来保证线程安全的,但在线程竞争激烈的情况下HashTable的效率下降得很快因为synchronized关键字会造成代码块或方法成为为临界区(对同一个对象加互斥锁),当一个线程访问临界区的代码时,其他线程也访问同一临界区时,会进入阻塞或轮询状态。究其原因,实际上是有获取锁意向的线程的数目增加,但是锁还是只有单个,导致大量的线程处于轮询或阻塞,导致同一时间段有效执行的线程的增量远不及线程总体增量。 


CocurrentHashMap利用锁分段技术增加了锁的数目,从而使争夺同一把锁的线程的数目得到控制。 
锁分段技术就是对数据集进行分段,每段竞争一把锁,不同数据段的数据不存在锁竞争,从而有效提高 高并发访问效率。
CocurrentHashMap在get方法是无需加锁的,因为用到的共享变量都采用volatile关键字修饰,保证共享变量在线程之间的可见性。
ConcurrentMap中不能保存value为null的值。
ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率之间的一种权衡。








java 中对象比较大小有两种方法 
1:实现Comparable 接口 的 public int compareTo(T o) 方法; 


2:实现Comparator 接口 的   int compare(T o1, T o2)方法;




ReentrantLock 与synchronized有相同的并发性和内存语义,还包含了中断锁等候和定时锁等候,意味着线程A如果先获得了对象obj的锁,那么线程B可以在等待指定时间内依然无法获取锁,那么就会自动放弃该锁。
 
但是由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否,而ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock();


synchronized的缺陷
  synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?


  在上面一篇文章中,我们了解到如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:


  1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;


  2)线程执行发生异常,此时JVM会让线程自动释放锁。


  那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。


  因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。


  再举个例子:当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。


  但是采用synchronized关键字来实现同步的话,就会导致一个问题:


  如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。


  因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。


  另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。


  总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:


  1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;


  2)Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。




     如果锁具备可重入性,则称作为可重入锁。像synchronized和ReentrantLock都是可重入锁,可重入性在我看来实际上表明了锁的分配机制:基于线程的分配,而不是基于方法调用的分配。


      synchronized就不是可中断锁,而Lock是可中断锁。
      如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。


    公平锁即尽量以请求锁的顺序来获取锁。
    非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。


  在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。


  而对于ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值