我用多线程同时处理一个key,value值结构的数据表,客户需求是这样的:要采用多线程来同时处理这些数据,但是如果与到key值相同的数据则要看目前有没有与之相同key的数据正在被处理中,如果有则等待之处理完毕后再进行,
我现在写了一个doSome(String key, String value)的方法,但是对这个方法加锁就不是多线程同时在处理了,主要就是这里面的key值应该怎么来处理这个方法的代码如下:
//public synchronized void doSome(Object key, String value) {
public void doSome(Object key, String value) { // 以下代码是需要局部同步的代码
{
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":" + (System.currentTimeMillis() / 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我现在写了一个doSome(String key, String value)的方法,但是对这个方法加锁就不是多线程同时在处理了,主要就是这里面的key值应该怎么来处理这个方法的代码如下:
//public synchronized void doSome(Object key, String value) {
public void doSome(Object key, String value) { // 以下代码是需要局部同步的代码
{
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":" + (System.currentTimeMillis() / 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
加锁怎么就不是多线程了,加锁只是为了解决共享资源的竞争问题,在一个线程占用该资源的时候另一个线程无法使用该资源
如果只是希望防止多线程同时访问方法内部部分代码而不是防止访问整个方法,可以使用临界区
就是在方法内部
synchronized (object){...要并发访问的代码}
另外你这个需求如果key值种类的数目有限的话我觉得可以用BlockingQueue来做会方便些
假如我起了4个线程来同时处理doSome的代码块,如果传递的key值都是不同的,那么这里面的打印语句应该是在同一时间打印出来,但是如果其中有2个线程传递的key值是相同的,那么应该是其中之一其它两线程一起执行这块代码,等待1移后再执行另外一个线程的此块代码。 如果对这块代码加了锁,那么这4个线程就会以每过1秒钟的顺序执行,这和单线程的效果是差不多的。
1:1:1256392306
3:3:1256392306
4:4:1256392306
1:2:1256392307
由于最后一个的key值与第一个相同,所以它等待第一个执行完毕后再运行,时间差1秒代码如下:
Test.javapublic class Test extends Thread{
private TestDo testDo;
private String key;
private String value;
public Test(String key,String key2,String value){
this.testDo = TestDo.getInstance();
this.key = new String(key+key2);
this.value = value;
}
public static void main(String[] args) throws InterruptedException{
Test a = new Test("1","","1");
Test b = new Test("1","","2");
Test c = new Test("3","","3");
Test d = new Test("4","","4");
System.out.println("begin:"+(System.currentTimeMillis()/1000));
a.start();
c.start();
d.start();
b.start();
}
public void run(){
testDo.doSome(key, value);
}
}public class TestDo {
private static TestDo _instance = new TestDo();
//private static ReentrantLock lock = new ReentrantLock ();
public static TestDo getInstance() {
return _instance;
}
//public synchronized void doSome(Object key, String value) {
public void doSome(Object key, String value) { // 以下代码是需要局部同步的代码
{
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":" + (System.currentTimeMillis() / 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private TestDo() { }
}
就是public void doSome(Object key, String value) {synchronized (key){
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":" + (System.currentTimeMillis() / 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
this.testDo = TestDo.getInstance();
this.key = key;
this.value = value;
}
我的那个方法是可行的,给你这样改了一下,测试通过了,主要你的key必须是在String池里取的,必须保证值相同的key的内存中的地址是相同的,这样运行是JVM才会对这两个key加同一个监视器
所以建议LZ把key改为一个,不要那样key+key2
intern
public String intern()返回字符串对象的规范化表示形式。
一个初始为空的字符串池,它由类 String 私有地维护。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。 它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。 所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。字符串字面值在 Java Language Specification 的 §3.10.5 定义。
返回:
一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。
上面的一位大哥 提示intern 想起来了String的这个特殊的方法只是 Key是String的情况!!package test1;public class TestDo
{
private static TestDo _instance = new TestDo();
String k;
//private static ReentrantLock lock = new ReentrantLock ();
public static TestDo getInstance()
{
return _instance;
}
//public synchronized void doSome(Object key, String value)
public void doSome(String key, String value)
{ k=key.intern();
// 以下代码是需要局部同步的代码
{
synchronized (k)
{
try {
Thread.sleep(1000);
System.out.println(k+":"+value + ":" + (System.currentTimeMillis() / 1000));
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
import java.util.Hashtable;
import java.util.Map;/**
*
* @author yidinghe
*/
public class Main { // 程序入口,测试 BlockingMap
public static void main(String[] args) {
final BlockingMap<String, String> map = new BlockingMap<String, String>(); map.put("1", "value 1");
map.put("2", "value 2"); map.execute("2", new BlockingMap.BlockingMapRunnable<String>() { public void run(String t) {
try {
System.out.println("Thread " + hashCode() + " is dealing with " + t);
Thread.sleep(1000);
} catch (InterruptedException ex) {
// nothing to do
}
}
}); for (int i = 0; i < 10; i++) {
new Thread() { @Override
public void run() {
map.execute("1", new BlockingMap.BlockingMapRunnable<String>() { public void run(String t) {
try {
System.out.println("Thread " + hashCode() + " is dealing with " + t);
Thread.sleep(1000); if (map.containsKey("2")) {
System.out.println("key 2 is removed.");
map.remove("2");
}
} catch (InterruptedException ex) {
// nothing to do
}
}
});
}
}.start();
}
}
}// 实现以阻塞方式处理 value 值的 Map
class BlockingMap<K, V> extends Hashtable<K, V> { private final Map<K, Object> locks = new HashMap<K, Object>(); @Override
public V remove(Object key) {
locks.remove(key);
return super.remove(key);
} // 对指定 key 值的 value 进行处理。处理逻辑需要实现 BlockingMapRunnable 接口。
public void execute(K key, BlockingMapRunnable<V> r) {
if (!containsKey(key)) {
return;
} synchronized (locks) {
if (!locks.containsKey(key)) {
System.out.println("Thread " +
Thread.currentThread().hashCode() +
" creates the lock.");
locks.put(key, new Object());
}
} synchronized (locks.get(key)) {
System.out.println("locks: " + locks);
r.run(get(key));
}
} // 对 value 进行处理的逻辑
public static interface BlockingMapRunnable<T> { void run(T t);
}
}