导航:首页 > 编程语言 > java行锁

java行锁

发布时间:2023-03-04 13:31:48

A. java解决数据库并发问题

几百人报名就叫并发吗?
概念错了!
几百人操作几百条互不相关的数据那个不叫并发,只有同时操作同一条数据的情况才叫并发。
如果两人同时修改同一条数据的话,那个要不就使用行锁(悲观锁),要不就用version(乐观锁)控制。
其它情况无需考虑的。

B. java中 请问我应该如何如何锁这段代码才符合要求

public Object getObject(String key,Object o) {
synchronized (map) {
if(map.get(key)==null) {
map.put(key,o)
}else {
return map.get(key);
}}// 格式没法弄,自己弄一下
}

// demol0326 的回答意思使用MyTest的实例来加锁,但是map是static的,无法锁住
// MyTest的多个实例在多个线程中的请求

//禾木双子 :如果A线程在getObject方法的第二行停止,此时B线程进入getObject后执行部分代码, 此时B线程停止,A线程启动,他不会执行'多线程处理', 仍然有线程线程安全问题,(想象一下更多的线程进入该方法的情况,num甚至会得到负值)

C. Java如何实现对Mysql数据库的行锁

下面通过一个例子来说明
场景如下:
用户账户有余额,当发生交易时,需要实时更新余额。这里如果发生并发问题,那么会造成用户余额和实际交易的不一致,这对公司和客户来说都是很危险的。
那么如何避免:
网上查了下,有以下两种方法:
1、使用悲观锁
当需要变更余额时,通过代码在事务中对当前需要更新的记录设置for update行锁,然后开始正常的查询和更新操作
这样,其他的事务只能等待该事务完成后方可操作
当然要特别注意,如果使用了Spring的事务注解,需要配置一下:

<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />

在指定代码处添加事务注解

@Transactional
@Override
public boolean increaseBalanceByLock(Long userId, BigDecimal amount)
throws ValidateException {
long time = System.currentTimeMillis();
//获取对记录的锁定
UserBalance balance = userBalanceDao.getLock(userId);
LOGGER.info("[lock] start. time: {}", time);
if (null == balance) {
throw new ValidateException(
ValidateErrorCode.ERRORCODE_BALANCE_NOTEXIST,
"user balance is not exist");
}
boolean result = userBalanceDao.increaseBalanceByLock(balance, amount);
long timeEnd = System.currentTimeMillis();
LOGGER.info("[lock] end. time: {}", timeEnd);
return result;
}

MyBatis中的锁定方式,实际测试该方法确实可以有效控制,不过在大并发量的情况下,可能会有性能问题吧
<select id="getLock" resultMap="BaseResultMap" parameterType="java.lang.Long">
<![CDATA[
select * from user_balance where id=#{id,jdbcType=BIGINT} for update;
]]>
</select>

2、使用乐观锁
这个方法也同样可以解决场景中描述的问题(我认为比较适合并不频繁的操作):
设计表的时候增加一个version(版本控制字段),每次需要更新余额的时候,先获取对象,update的时候根据version和id为条件去更新,如果更新回来的数量为0,说明version已经变更
需要重复一次更新操作,如下:sql脚本

update user_balance set Balance = #{balance,jdbcType=DECIMAL},Version = Version+1 where Id = #{id,jdbcType=BIGINT} and Version = #{version,jdbcType=BIGINT}

这是一种不使用数据库锁的方法,解决方式也很巧妙。当然,在大量并发的情况下,一次扣款需要重复多次的操作才能成功,还是有不足之处的。不知道还有没有更好的方法。

D. 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行锁相关的资料

热点内容
反诈骗app怎么找回密码 浏览:631
java方法和函数 浏览:418
程序员衣服穿反 浏览:959
java多类继承 浏览:157
怎么用多玩我的世界连接服务器地址 浏览:483
为什么华为手机比安卓流畅 浏览:177
javamap多线程 浏览:228
卡西欧app怎么改时间 浏览:843
jquery压缩图片 浏览:970
用纸筒做解压东西 浏览:238
神奇宝贝服务器如何tp 浏览:242
云服务器支持退货吗 浏览:277
贷款等额本息算法 浏览:190
根服务器地址配置 浏览:501
单片机是软件还是硬件 浏览:624
vivo手机怎么看编译编号 浏览:320
塑钢扣条算法 浏览:301
linux应用程序安装 浏览:414
linux怎么查找命令 浏览:431
安卓12原生和非原生是什么意思 浏览:277