确保按顺序采用Java同步锁?

时间:2009-11-26 10:20:15

标签: java multithreading synchronization

我们有两个线程通过synchronized方法访问一个列表。我们可以吗

a)依靠运行时间来确保每个人都可以根据他们尝试的顺序获得对该方法的访问权或

b)VM是否遵循任何其他规则

c)是否有更好的方法来序列化请求?

7 个答案:

答案 0 :(得分:19)

不,synchronized将以任何顺序提供访问权限(取决于JVM实现)。这甚至可能导致线程在某些情况下挨饿。

您可以使用ReentrantLock(自Java 5.0起)使用fair=true选项来确保订单。 (Lock lock = new ReentrantLock(true);

答案 1 :(得分:11)

不,您无法确定是否会按顺序对同步方法进行两次调用。订单未指定且依赖于实现。

这是在JLS的17.1 Locks部分中定义的。请注意,没有提及等待锁的线程应该获得访问权的顺序。

答案 2 :(得分:3)

您不能依赖于从每个线程调用特定方法的顺序。如果只有两个线程可能是肯定的。但想象一下,如果有3个线程和1个线程已经获得访问权限。当他们尝试访问时,其他2个线程将等待,并且其中任何一个都可以获得访问权限,这并不取决于他们调用此方法的顺序。 因此,不建议依赖订单。

答案 3 :(得分:0)

  

c)是否有更好的方法来序列化请求?

您是否有可能将列表用作队列,即使用模式是否看起来像这样?

while (some condition) {
    synchronized(theList){
        anItem = get and remove an element from theList
    }
    do some work with anItem
}

如果是这样,您可能需要查看BlockingQueue界面,而不是使用自己的锁定方案。实现(如ArrayBlockingQueue)具有公平性等设置。

答案 4 :(得分:0)

我总是将同步发送到应用服务器或引擎,除非定义自己的强度

答案 5 :(得分:0)

我用几个仪器解决了类似的问题。我试图解决的问题是乒乓球服务。两个线程一个打印Ping,另一个打印Pong。但它们必须是顺序的。 (没有双重Ping或双重Pong)

我将在此处放置一个实现,但您可以看看其他实现(目前有6或7种不同的方式) https://github.com/tugrulkarakaya/pingpong

import java.util.concurrent.*;

public class Method2CyclicBarrier {

ExecutorService service;
CyclicBarrier c1 = new CyclicBarrier(2);
CyclicBarrier c2 = new CyclicBarrier(2);

public static void main(String[] args) {
    Method2CyclicBarrier m = new Method2CyclicBarrier();
    m.runPingPong();
}

public void runPingPong(){
    service = Executors.newFixedThreadPool(2);
        service.submit(() -> this.printPing(c1, c2));
        service.submit(() -> this.printPong(c1, c2));
}



public void printPing(CyclicBarrier c1, CyclicBarrier c2) {
    while(!Thread.currentThread().isInterrupted()) {
        try {
            c1.await();
            System.out.println("PING");
            c2.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        catch(BrokenBarrierException ex){

        }
    }
}

public void printPong(CyclicBarrier c1, CyclicBarrier c2){
    while(!Thread.currentThread().isInterrupted()) {
        try {
            c1.await();
            c2.await();
            System.out.println("PONG");
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        } catch(BrokenBarrierException ex){

        }
    }
}
}

答案 6 :(得分:-1)

如果通过一个同步方法访问列表,则将序列化来自多个线程的并发请求。