【问题标题】:What is the difference between synchronized and static synchronized?同步和静态同步有什么区别?
【发布时间】:2009-10-08 07:04:13
【问题描述】:

对于一个有 100 个并发用户登录的旅行预订 Web 应用程序, 订票和生成“电子票号”应该通过“同步”还是“静态同步”的方式实现?

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

    那么,你知道静态方法和一般实例方法之间的区别吗?

    synchronized 的唯一区别是,在 VM 开始运行该方法之前,它必须获取一个监视器。对于实例方法,获取的锁与您正在调用该方法的对象相关联。对于静态方法,获取的锁与类型本身相关联 - 因此没有其他线程能够同时调用任何其他同步的静态方法。

    换句话说,这个:

    class Test
    {
        static synchronized void Foo() { ... }
    
        synchronized void Bar() { ... }
    }
    

    大致相当于:

    class Test
    {
        static void Foo()
        {
            synchronized(Test.class)
            {
                ...
            }
        }
    
        void Bar()
        {
            synchronized(this)
            {
                ...
            }
        }
    }
    

    通常我根本不使用同步方法——我更喜欢在私有锁引用上显式同步:

    private final Object lock = new Object();
    
    ...
    
    void Bar()
    {
        synchronized(lock)
        {
            ...
        }
    }
    

    您没有提供足够的信息来确定您的方法应该是静态方法还是实例方法,或者它是否应该完全同步。多线程是一个复杂的问题 - 我强烈建议您阅读它(通过书籍、教程等)。

    【讨论】:

    • 如果是旅游预订网站,有100个并发用户。那么机票预订和生成“电子票号”功能应该在“同步”块或“静态同步”块中实现?
    • 你的问题和这个重复的评论都是没有意义的。如果 Jon Skeet 的出色回答未能满足您的需求,请重新表述您的问题。
    • 出于好奇:它如何“大致”等效?我的印象是有效执行是相同的(即使方法上的“同步”变成了一个标志而不是一些字节码指令(同步块变成了))。
    • @Joachim: 我有一种感觉 JVM 会确保线程在被获取之前根本不会进入同步方法锁 - 所以如果它死锁,堆栈跟踪将在顶层显示调用方法。使用同步 in 方法,该方法将位于顶部。不过我可能是错的——而且可能还有其他我不知道的微妙之处。
    【解决方案2】:

    Jon 的回答涵盖了您的问题标题中暗示的差异。

    但是,我想说都不应该使用来生成票号。假设这些被存储在数据库中的某个地方 - 数据库应该负责在您插入新记录时生成数字(可能是通过自动递增的主键或类似的东西)。

    如果您必须在 Java 代码中生成数字,我怀疑如果有 100 个并发用户,同步开销可能会非常明显。如果您在 Java 1.5 或更高版本上运行,我会使用 java.util.concurrent.AtomicInteger 来获取票号,您可以简单地调用它

    private static final AtomicInteger ticketSequence;
    
    static
    {
        final int greatestTicket = getHighestExistingTicketNumber(); // May not be needed if you can start from zero each time
        ticketSequence = new AtomicInteger(greatestTicket + 1);
    }
    
    public /*static*/ int getNextTicketNumber()
    {
        return ticketSequence.incrementAndGet();
    }
    

    这以比每次需要整数时同步更有效的方式为您提供所需的并发全局唯一性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-22
      • 2011-01-09
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多