java乐观锁代码 乐观锁version的实现

Java锁有哪些种类,以及区别一、公平锁/非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁 。
非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁 。有可能 , 会造成优先级反转或者饥饿现象 。
对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁 。非公平锁的优点在于吞吐量比公平锁大 。
对于Synchronized而言,也是一种非公平锁 。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁 。
二、可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁 。说的有点抽象,下面会有一个代码的示例 。
对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁,其名字是Re entrant Lock重新进入锁 。
对于Synchronized而言,也是一个可重入锁 。可重入锁的一个好处是可一定程度避免死锁 。
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB();
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
上面的代码就是一个可重入锁的一个特点,如果不是可重入锁的话 , setB可能不会被当前线程执行 , 可能造成死锁 。
三、独享锁/共享锁
独享锁是指该锁一次只能被一个线程所持有 。
共享锁是指该锁可被多个线程所持有 。
对于Java
ReentrantLock而言,其是独享锁 。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁 。
读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的 。
独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享 。
对于Synchronized而言,当然是独享锁 。
四、互斥锁/读写锁
上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现 。
互斥锁在Java中的具体实现就是ReentrantLock
读写锁在Java中的具体实现就是ReadWriteLock
五、乐观锁/悲观锁
乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度 。
悲观锁认为对于同一个数据的并发操作 , 一定是会发生修改的,哪怕没有修改 , 也会认为修改 。因此对于同一个数据的并发操作 , 悲观锁采取加锁的形式 。悲观的认为,不加锁的并发操作一定会出问题 。
乐观锁则认为对于同一个数据的并发操作,是不会发生修改的 。在更新数据的时候,会采用尝试更新,不断重新的方式更新数据 。乐观的认为,不加锁的并发操作是没有事情的 。
从上面的描述我们可以看出,悲观锁适合写操作非常多的场景 , 乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升 。
悲观锁在Java中的使用,就是利用各种锁 。
乐观锁在Java中的使用,是无锁编程 , 常常采用的是CAS算法 , 典型的例子就是原子类,通过CAS自旋实现原子操作的更新 。
六、分段锁
分段锁其实是一种锁的设计,并不是具体的一种锁 , 对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作 。
我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想,ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组 , 数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock) 。
当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中 , 然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入 。
但是 , 在统计size的时候,可就是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计 。
分段锁的设计目的是细化锁的粒度 , 当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作 。
七、偏向锁/轻量级锁/重量级锁
这三种锁是指锁的状态,并且是针对Synchronized 。在Java
5通过引入锁升级的机制来实现高效Synchronized 。这三种锁的状态是通过对象监视器在对象头中的字段来表明的 。
偏向锁是指一段同步代码一直被一个线程所访问 , 那么该线程会自动获取锁 。降低获取锁的代价 。
轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁 , 其他线程会通过自旋的形式尝试获取锁,不会阻塞 , 提高性能 。
重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁 , 就会进入阻塞,该锁膨胀为重量级锁 。重量级锁会让其他申请的线程进入阻塞,性能降低 。
八、自旋锁
在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗 , 缺点是循环会消耗CPU 。
典型的自旋锁实现的例子,可以参考自旋锁的实现
java多用户同时修改一条数据时乐观锁怎么用的?java乐观锁代码你说java乐观锁代码的这个version是mysql底层的锁机制提供的java乐观锁代码,并不是java提供的 。
使用数据版本(Version)记录机制实现,这是mysql乐观锁最常用的一种实现方式 。所谓的数据版本就是给数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现 。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加1 。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,版本号重新读取再做更新 。
java lock和synchorinzed的区别一、synchronized和lock的用法区别
synchronized:在需要同步的对象中加入此控制,synchronized可以加在方法上 , 也可以加在特定代码块中,括号中表示需要锁的对象 。
lock:需要显示指定起始位置和终止位置 。一般使用ReentrantLock类做为锁 , 多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效 。且在加锁和解锁处需要通过lock()和unlock()显示指出 。所以一般会在finally块中写unlock()以防死锁 。
用法区别比较简单,这里不赘述了,如果不懂的可以看看Java基本语法 。
二、synchronized和lock性能区别
synchronized是托管给JVM执行的,而lock是java写的控制锁的代码 。在Java1.5中,synchronize是性能低效的 。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多 。相比之下使用Java提供的Lock对象,性能更高一些 。但是到了Java1.6,发生了变化 。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等 。导致在Java1.6上synchronize的性能并不比Lock差 。官方也表示 , 他们也更支持synchronize,在未来的版本中还有优化余地 。
说到这里,还是想提一下这2中机制的具体区别 。据我所知 , synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁 。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁 。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低 。
而Lock用的是乐观锁方式 。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止 。乐观锁实现的机制就是CAS操作(Compare and Swap) 。我们可以进一步研究ReentrantLock的源代码,会发现其中比较重要的获得锁的一个方法是compareAndSetState 。这里其实就是调用的CPU提供的特殊指令 。
现代的CPU提供了指令,可以自动更新共享数据 , 而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定 。这个算法称作非阻塞算法,意思是一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法 。
我也只是了解到这一步,具体到CPU的算法如果感兴趣的读者还可以在查阅下 , 如果有更好的解释也可以给我留言,我也学习下 。
三、synchronized和lock用途区别
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候 。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
java中悲观锁和乐观锁的区别乐观锁和悲观锁的区别如下:
1、悲观锁是当线程拿到资源时,就对资源上锁,并在提交后,才释放锁资源,其他线程才能使用资源 。
【java乐观锁代码 乐观锁version的实现】2、乐观锁是当线程拿到资源时,上乐观锁,在提交之前,其他的锁也可以操作这个资源,当有冲突的时候 , 并发机制会保留前一个提交,打回后一个提交,让后一个线程重新获取资源后 , 再操作,然后提交 。和git上传代码一样,两个线程都不是直接获取资源本身,而是先获取资源的两个copy版本,然后在这两个copy版本上修改 。
3、悲观锁和乐观锁在并发量低的时候,性能差不多,但是在并发量高的时候,乐观锁的性能远远优于悲观锁 。
4、常用的synchronized是悲观锁,lock是乐观锁 。
java乐观锁代码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于乐观锁version的实现、java乐观锁代码的信息别忘了在本站进行查找喔 。

    推荐阅读