多线程并发求教
例:
A转账给B,
C转账给B.
........
入库操作.
1.需要效率,不能把没有冲突的人给锁住,比如:e转账给f,这个时候,ab,ef同时进行,对于A->b做完后才能C->B.
2.暂时想法是把正在进行的人员放入到一个静态的map中(成对放入,比如A,B),
每次先检查要处理的人是否有其中一个正在处理,如果正在处理,那么循环等.如果正在处理的人,处理完了,那么就从map中移除出去,后来的C->B就放入....依次循环..
但如果真的并发了那么放入map的时候可能出现并发,但我不能去锁方法,锁方法就违背了第一个.
其实也不止放的时候,判断map是否存在该人,放入时,删除时,都存在并发的问题.
谁有并发的处理经验?求教.
以这个例子再次说明下:
A->B
C->B
E->F
期望,如果三对同时做的话,那么a,b和e,f先处理,c,b等待.
但愿大家明白我意思.
[解决办法]
楼主可以去看下java.util.concurrent.locks包下的
Lock类和Condition类jdk 1.5新线程同步类。
[解决办法]
其实我觉得从理论上来说,这种既能兼顾效率又能兼顾一致性的并发解决方案并不存在,因为计算机无论任何的逻辑判断过程都是需要时间复杂度的,这是肯定的,只要有时间复杂度,就一定存在并发问题,要解决并发,就必须要加锁,这是没有商量的,但是第一条又要求不能对无影响的用户加锁,如何判断有没有影响呢?当然是通过程序,但是程序又需要时间来执行,执行过程中又会有并发......这是一个悖论
[解决办法]
public interface Transfer {
void action(Transfer transfer);
}
public class TransferImp implements Transfer {
public synchronized action(Transfer transfer) {
synchronized (transfer) {
...
}
}
}
public class TransferThread implements Runnable {
private Transfer from;
private Transfer to;
public TransferThread(Transfer from, Transfer to) {
this.from = from;
this.to = to;
}
public void run() {
from.action(to);
}
}
public class Test {
public void static main(String[] args) {
// 如果是Web环境下你只要将地下申明的a,b,c,e,f对象放入全局就行(如static,application,session等),根据你实际情况
Transfer a = new TransferImp();
Transfer b = new TransferImp();
Transfer c = new TransferImp();
Transfer e = new TransferImp();
Transfer f = new TransferImp();
Thread t1 = new Thread(new TransferThread(a,b));
Thread t2 = new Thread(new TransferThread(c,b));
Thread t3 = new Thread(new TransferThread(e,f));
t1.start();
t2.start();
t3.start();
}
}
[解决办法]
该回复于2012-11-12 19:04:45被管理员删除
[解决办法]
人员为N,你这个就不是很可取了,有人来注册了,就是多一个人了,像你这么做,别人不操作的你也new出来了,压力太大.
[解决办法]
楼主这个问题,如果把锁挂在每个人头上,就能尽量地避免冲突了。
只要保证对同一个人的操作都是在同一个对象上,不同人的操作在不同的对象上,就可以实现同步一个人,而不影响其他人了。
可以把Person对象都放在一个全局的PersonMap中,需要操作的时候从PersonMap中获取,保证只有一个人只有实例。如果楼主觉得效率低,也可以搞个优化,定时清理PersonMap中那些不用的Person。
下面代码模拟了一下,至于Map的问题可以另外优化。
public class Translate extends Thread{
private Person p1;
private Person p2;
private int money;
public Translate(Person p1, Person p2, int money) {
this.p1 = p1;
this.p2 = p2;
this.money = money;
}
@Override
public void run() {
try {
p1.del(money);
p2.add(money);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Person pA = new Person("A", 200);
Person pB = new Person("B", 200);
Person pC = new Person("C", 200);
Person pD = new Person("D", 200);
Translate t1 = new Translate(pA, pB, 20);
Translate t2 = new Translate(pC, pB, 20);
Translate t3 = new Translate(pC, pD, 20);
t1.start();
t2.start();
t3.start();
}
}
class Person {
private double account;
private String name;
public Person(String name, double account) {
this.account = account;
this.name = name;
}
public synchronized void add(double money) throws InterruptedException {
account += money;
printMenoy("add");
Thread.sleep(2000); // 处理时间,通过这来看出其他线程的阻塞
}
public synchronized void del(double money) throws InterruptedException {
account -= money;
printMenoy("delete");
}
public void printMenoy(String deal) {
System.out.println("Deal with: " + deal + " -- " + name + "'s money :" + account);
}
}
[解决办法]
上面有一句没写通顺:
就是PersonMap中,保证每个人只有一个实例
[解决办法]
哎,你们说的这些并发的时候根本不可取!
[解决办法]
我只知道有线程安全和线程不安全之分.
[解决办法]
楼主啊,稍微改变下就能在你的实际情况中使用了,我在上面给你的建议不是书本上学来的,是实践中得来的。效率还可以,但最重要的是线程安全。你提出的思路,线程安全很难控制。
没有人跟你说要一口气将所有的行记录转换成静态对象放在内存,也没有人跟你说静态放在内存中的对象要一直存活。这中间你要根据你的实际情况灵活管理的。
------解决方案--------------------
看出来了,你是书上学来的,但是你这个模型不符合我的模型.我必须为成对出现.
今天找了个模型,差不多,测试中.
[解决办法]
我说的为什么不可取呢?
[解决办法]
呵呵,仔细看题目,AB做的时候,CB就要等待,因为AB没有做完.一对人为一次完整的交易,
你的做法两个B同时做了.
若,放到map中,先不说人有多么的多的问题.
map移除和获取并发的时候就已经出问题了.(别告诉我说用hashTable,更别告诉我用Collections.synchronizedMap(new LinkedHashMap<K, V>()))
[解决办法]
好,放到静态对象中又牵扯出来一个问题,对于静态对象我添加和移除的时候又有并发现象.然后又着手进行静态对象进行加锁处理...
看了一些并发模型,这个被划到多线程间通信的问题里了.数据就是通信内容,保证内容的获取和移除不产生死锁就行了.暂时找了个,测试中....
[解决办法]
谢谢各位的热心解答,这个问题,至少也要用wait(),notify() 吧?至少我现在找的模型都用了.要不然后来的线程怎么实现等待?大家好好想想.
[解决办法]
我的处理,B操作的时候是被锁住的,所以CB要等AB完成才做的,你没看清楚。(可能你的意思是C动了…)
另外你说Map的问题,是存在,不过现在1.5可以用ConcurrentHashMap,这个还是快了不少。
本来你要减少冲突,就不得不牺牲其他性能。何况这里只是做一下人的缓存,比你说的多人冲突,等待效率更定要好。
[解决办法]
仔细看了下,你的B是锁住了,但你的add和del是分开的,我说了要成对,你这个就破坏了原子性,
想:
当ab来的时候,处理到a的时候,a完,正在处理B,这个时候又来,ac,你的a又处理了,但ab这对没有处理完啊?
并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发并发
[解决办法]
我在13楼中已经说明如果你用
hashMap或
Collections.synchronizedMap(new LinkedHashMap())或
ConcurrentHashMap都会产生异常的问题,
要保证效率,不能将锁的范围扩大.
你说B是锁住了,对,是锁住了,所有人都进不来了,该进来的也进不来了!
[解决办法]
先恭喜你找到解决方案。
你的这个案例不需要用到wait和notify的(他们最适合的场合是生产者消费者模式),当然用它也会有解决方案。
我不强制你要接受我的方案,不过我还是认为我那方案相对还是不错的,从你回复的内容来看你还没完全理解我给你提出的方案,你说的问题,根本就不是问题。
讨论到此为止吧。
