Java 同步块(synchronized block)未按预期工作

标签 java multithreading

我正在尝试使用映射来实现线程 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/

相关文章:

java - 导入另一个 spring 上下文时的 spring bean 名称

java - 包导入/编译不起作用

java - 客户端使用具有用户名 token 安全性的 WSO2 WSAS Web 服务

JavaFX 简单更新标签(线程)

python - 扭曲: `defer.execute` 和 `threads.deferToThread` 之间的区别

Swift - 强制同步执行工作和后续 UI 渲染

2 台 PC 之间的 Java RMI

java - 尝试从扫描仪读取时文件内容被删除

android - 从非 UI 线程更新 View

multithreading - 模拟器上的单核多线程