[英]Java synchronized block not working as expected
我正在嘗試使用映射來實現線程塊,以便一次只能對一個客戶進行一次以上的操作。 這是與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,以便在線程有時間完成之前不會退出單元測試。
someThread.run()
不是啟動線程的方法。 它僅在任何后續行之前在當前線程內運行該線程的內部可運行對象。 使用.start()
實際將線程作為線程啟動,並讓兩個線程(和主線程)同時運行。
Thread#run()
是常規的同步方法調用。 您需要的是Thread#start()
,它執行native
調用以啟動OS線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.