java 线程安全问题

SandKing 发布于 2014/09/03 12:37
阅读 869
收藏 1
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种,还有什么好的处理方式呢!






加载中
0
SandKing
SandKing
我做的是不是一个功能,而是想封装一个框架,最大的简化逻辑层的代码!
SandKing
SandKing
回复 @sxgkwei : 我只能 呵呵。。。
sxgkwei
sxgkwei
逻辑层的代码?这个都能简化?既然叫做逻辑层,那就说明是跟着具体业务逻辑走的。这个完全没有可简化空间吧?
0
0
长安俞白眉
长安俞白眉
根本没有耐心看完
0
暗影风暴
暗影风暴
不知道我说的对不对,因为我没看完你贴的代码,感觉你把问题想复杂了。我感觉在dao这块,不必使用线程安全吧,数据库的锁机制应该满足要求了吧,大不了搞搞约束和事务处理,个人感觉实在没必要控制线程,容易出现死锁甚至影响效率
优雅先生
优雅先生
回复 @SandKing : 进程级的内存?新名词?
SandKing
SandKing
我那个DAO只是一个简单的例子! 我要做的是进程级的内存!
0
k
kidding
楼主需要的是数据库的隔离级别
0
安西都护府首席程序员
安西都护府首席程序员
你的synchronized 锁的是对象,但是你两个线程分别返回了不同的对象,因此互不影响,所以你的synchronized当然没有效果了
SandKing
SandKing
用只是举例说明。。。
吐槽的达达仔
吐槽的达达仔
根本不是synchronized的问题,你这里是不是想做单例??通过单机的内存来管理JVM中只存在一个对象??
安西都护府首席程序员
安西都护府首席程序员
回复 @SandKing : 是啊,那你怎么还用
SandKing
SandKing
所以我才说,synchronized对于我的这个需求无用!
0
lock_free
lock_free
数据有共享才有线程安全性问题,文中提到的问题应该是数据库层面的问题。
  1. jvm 层面数据共享产生的线程安全问题-synchronized,lock, volatile
  2. 数据库的共享数据的并发修改-悲观锁,乐观锁。数据库的事务隔离级别。
  3. 缓存的更新问题
SandKing
SandKing
嗯,我就是把数据库的数据映射到JVM中,然后缓存。多线程数据共享!采用的乐观锁!更新缓存!
0
我不说话
我不说话

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

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

返回顶部
顶部