我正在尝试使用映射实现线程块,以便一次只能在一个客户上处理一个操作。这是与Web服务的对话,需要多个步骤才能完成整个工作流程。我需要能够一次锁定一个客户,但允许其他线程执行而不会阻止流程。
以下是我的测试用例,了解如何使其正常运行。我所看到的是第二个线程无法进入doSynchronizedSomething
的同步块,直到第一个线程被清除。我认为这应该有效,但它没有按预期工作。
以下是结果,您会发现毫秒相距三秒钟。我还检查了以确保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,以便在线程有时间完成之前单元测试不会退出。
答案 0 :(得分:5)
someThread.run()
不是启动线程的方法。它只在当前线程中运行该线程的内部可运行,然后才能在任何后续行之前运行。使用.start()
实际将线程作为线程启动,并让两个线程(和主线程)同时运行。
答案 1 :(得分:4)
Thread#run()
是正常的同步方法调用。你想要的是Thread#start()
,它执行native
调用来启动操作系统线程。