簡體   English   中英

Java同步塊無法按預期工作

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM