我正在尝试使用映射来实现线程 block ,以便一次只能对一个客户处理一个操作。这是与 Web 服务对话,需要多个步骤才能完成完整的工作流程。我需要能够一次锁定一个客户,但允许其他线程执行而不阻塞流程。
这是我的测试用例,看看如何让它工作。我看到的是,在第一个线程清除之前,第二个线程无法进入 doSynchronizedSomething 的同步块(synchronized block)。我认为这应该有效,但它没有按预期工作。
这是结果,您会注意到毫秒间隔三秒。我还检查以确保 CustomerLocks
与我的测试用例中的对象不同。这可能吗?
Starting operation 123456 at time 1381173121688
Done with operation for 123456 at time 1381173124689
Starting operation 234567 at time 1381173124689
Done with operation for 234567 at time 1381173127690
代码
package simplethreadlock;
public class CustomerLock {
private String customerId;
public CustomerLock(String customerId) {
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
}
package simplethreadlock;
import java.util.concurrent.ConcurrentHashMap;
public class CustomerLockingMap {
private static ConcurrentHashMap<String, CustomerLock> locks = new ConcurrentHashMap<String, CustomerLock>();
public static CustomerLock aquireLock(String customerId) {
CustomerLock lock = locks.get(customerId);
if (lock == null) {
lock = new CustomerLock(customerId);
locks.put(customerId, lock);
}
return lock;
}
}
package simplethreadlock;
import org.junit.Assert;
import org.junit.Test;
public class CutomerLockingTest {
@Test
public void testLock() throws InterruptedException {
final String customerId1 = "123456";
final String customerId2 = "234567";
final CustomerLock customer1Lock1 = CustomerLockingMap
.aquireLock(customerId1);
final CustomerLock customer1Lock2 = CustomerLockingMap
.aquireLock(customerId1);
final CustomerLock customer2Lock1 = CustomerLockingMap
.aquireLock(customerId2);
final CustomerLock customer2Lock2 = CustomerLockingMap
.aquireLock(customerId2);
CountDownLatch latch = new CountDownLatch(1);
Assert.assertNotEquals(customer1Lock1, customer2Lock1);
new Thread(new Runnable() {
public void run() {
try {
doSynchronziedSomething(customer1Lock1, customerId1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
doSynchronziedSomething(customer2Lock1, customerId2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
doSynchronziedSomething(customer1Lock2, customerId1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
doSynchronziedSomething(customer2Lock2, customerId2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
latch.await(8, TimeUnit.SECONDS);
}
private void doSynchronziedSomething(final CustomerLock lock, final String customerId) throws InterruptedException {
synchronized (lock) {
System.out.println("Starting operation " + customerId + " at time "
+ System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("Done with operation for " + customerId
+ " at time " + System.currentTimeMillis());
}
}
}
编辑
愚蠢的是,它是 Thread.start() 但如果您正在查看示例以寻求帮助,我确实添加了 CountDownLatch,以便单元测试不会在线程有时间完成之前退出。
最佳答案
someThread.run()
不是启动线程的方法。它仅在任何后续行之前运行当前线程内该线程的内部可运行程序。使用.start()
真正将线程作为一个线程启动,并让两个线程(和主线程)同时运行。
关于Java 同步块(synchronized block)未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19232798/