java 线程安全问题:报错 -问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

java 线程安全问题:报错

kun坤 2020-06-09 23:07:33 115

java线程安全的处理我知道的现在就2种

lock、synchronized

我想线程安全封装在我框架的底层。但是在开发中我始终有个疑问

比如我有这样一个对象


public class User {
	private int id;
	private String name;
	private int money;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
}



我现在需要查询 UserDao 类



public class UserDao {
	public User getById(int id){
		...
	}
	
	public User getByType(int type){
		...
	}
}



我查询出来会执行修改,而为了保证我数据的安全 synchronized此时感觉就没多大用了(我查询出来返回的是原数据的一个clone对象)


为何synchronized不起作用呢?下面代码解释

public class A_Thread implements Runnable{
	public void run() {
		//此时查询出来的数据是原数据的一个clone 原数据再怎么变这个对象也不会受影响
		User user = UserDao.getById(1);
		Thread.sleep(1000);
		user.setMoney(user.getMoney()+10);
		user.update();
	}
}

public class B_Thread implements Runnable{
	public void run() {
		//此时查询出来的数据是原数据的一个clone 原数据再怎么变这个对象也不会受影响
		User user = UserDao.getById(1);
		Thread.sleep(1000);
		user.setMoney(user.getMoney()+10);
		user.update();
	}
}

public class Test{
	public static void main(String[] agrs){
		ExecutorService exe = Executors.newFixedThreadPool(8);
		exe.execute(new A_Thread());
		exe.execute(new B_Thread());
	}
}


public static void main(String[] agrs){
		User user = UserDao.getById(1);
		int money = user.getMoney();
		money = ???
	}

结果这个user的 值根本确定不了 无论在那加 synchronized

public synchronized int getMoney() {
		return money;
	}
	public synchronized void setMoney(int money) {
		this.money = money;
	}

到这大概有人会说把User保留一分在内存中,查询始终,修改始终都是操作的内存中这个User对象!

但会有以下几个问题

1.数据会出出现完整性问题(多线程并发的时候 你一个逻辑线程需要set 10属性,但才3个,另外一个逻辑线程要取这个对象,那个瞬间他取过去的数据实际上就只改了3个属性)
2.如果我set了 但是update失败!但是内存中的数据任然有部分已经受到了影响

好了!synchronized不能很好的解决我的问题,那么我就来用Lock。Lock必须显示的加锁和放锁

我要防止上面的问题,在比如getById()的时候就有了2中加锁方式,加读锁和写锁。我需要修改的查询就在调用getById中加上写锁,只读不修改的时候就加读锁。而现在问题又来了
并且我是加在User的实例对象上的,加载Dao也可以但性能会底很多!
1.我加了写锁之后必须等我逻辑线程处理完后 简单的说就是要 update之后才能放锁!

2.如果逻辑线程在取得写锁后逻辑出现异常了!导致没有换锁!

解决这个我的处理试了一下几种

1.加了个最大持有该锁的时间,当另外一个线程要获得该锁的时候检查时间,如果超过时间,中断持有改锁的线程(不大友好)

2.定时检查,但并发高的时候会有很多定时器

3.改造getById(int id)方法,getById(int id,List<Lock> locks) 在查询中传一个List进去,把该次操作的的Lock反馈出来,在逻辑处理完后全部释放!

List<Lock> locks = new ArrayList();
		try {
			//业务逻辑
			getById(1,locks);
		} catch (Exception e) {
			
		}finally{
			//locks 全部释放掉
		}



我想问下你们一般线程安全是怎么处理的呢!还有除了我说的3种,还有什么好的处理方式呢!






安全 Java
分享到
取消 提交回答
全部回答(1)
  • kun坤
    2020-06-09 23:07:40

    我做的是不是一个功能,而是想封装一个框架,最大的简化逻辑层的代码!######回复 @sxgkwei : 我只能 呵呵。。。######逻辑层的代码?这个都能简化?既然叫做逻辑层,那就说明是跟着具体业务逻辑走的。这个完全没有可简化空间吧?######事务?######没人?######根本没有耐心看完######不知道我说的对不对,因为我没看完你贴的代码,感觉你把问题想复杂了。我感觉在dao这块,不必使用线程安全吧,数据库的锁机制应该满足要求了吧,大不了搞搞约束和事务处理,个人感觉实在没必要控制线程,容易出现死锁甚至影响效率######回复 @SandKing : 进程级的内存?新名词?######我那个DAO只是一个简单的例子! 我要做的是进程级的内存!######楼主需要的是数据库的隔离级别######你的synchronized 锁的是对象,但是你两个线程分别返回了不同的对象,因此互不影响,所以你的synchronized当然没有效果了######用只是举例说明。。。######根本不是synchronized的问题,你这里是不是想做单例??通过单机的内存来管理JVM中只存在一个对象??######回复 @SandKing : 是啊,那你怎么还用######所以我才说,synchronized对于我的这个需求无用!######数据有共享才有线程安全性问题,文中提到的问题应该是数据库层面的问题。

    1. jvm 层面数据共享产生的线程安全问题-synchronized,lock, volatile
    2. 数据库的共享数据的并发修改-悲观锁,乐观锁。数据库的事务隔离级别。
    3. 缓存的更新问题
    ######嗯,我就是把数据库的数据映射到JVM中,然后缓存。多线程数据共享!采用的乐观锁!更新缓存!######

    1、同步 数据层的查询和更新方法。或者业务逻辑层的方法

    2、sql语句,查询时+ for update

    ###### 请参考: 线程安全的判定
    0 0
+ 订阅

云安全开发者的大本营

推荐文章
相似问题
推荐课程