0

我正在尝试使用映射实现一个线程块,以便一次只能在一个客户上处理一个以上的操作。这是与 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 以便在线程有时间完成之前单元测试不会退出。

4

2 回答 2

5
someThread.run()

不是启动线程的方法。它仅在任何后续行之前在当前线程中运行该线程的内部可运行文件。用于.start()实际启动线程作为线程,并让两个线程(和主线程)同时运行。

于 2013-10-07T19:24:20.023 回答
4

Thread#run()是一个普通的同步方法调用。您想要的是Thread#start()执行native调用以启动 OS 线程。

于 2013-10-07T19:24:23.800 回答