线程同步 - 线程何时释放对象的锁定

sam*_*sam 5 java multithreading thread-synchronization

public class MyStack2 {
    private int[] values = new int[10];
    private int index = 0;

    public synchronized void push(int x) {
        if (index <= 9) {
            values[index] = x;
            Thread.yield();
            index++;
        }
    }

    public synchronized int pop() {
        if (index > 0) {
            index--;
            return values[index];
        } else {
            return -1;
        }
    }

    public synchronized String toString() {
        String reply = "";
        for (int i = 0; i < values.length; i++) {
            reply += values[i] + " ";
        }
        return reply;
    }
}

public class Pusher extends Thread {
    private MyStack2 stack;

    public Pusher(MyStack2 stack) {
        this.stack = stack;
    }

    public void run() {
        for (int i = 1; i <= 5; i++) {
            stack.push(i);
        }
    }
}

public class Test {
    public static void main(String args[]) {
        MyStack2 stack = new MyStack2();
        Pusher one = new Pusher(stack);
        Pusher two = new Pusher(stack);
        one.start();
        two.start();
        try {
            one.join();
            two.join();
        } catch (InterruptedException e) {
        }
        System.out.println(stack.toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

由于MyStack2类的方法是同步的,我期望输出为1 2 3 4 5 1 2 3 4 5.但输出是不确定的.通常它给出:1 1 2 2 3 3 4 4 5 5

根据我的理解,当线程1启动时,它获取push方法的锁定.内部push()线程一个产生一段时间.但它在yield()被叫时是否释放锁定?现在当线程2启动时,线程2会在线程一完成执行之前获取一个锁吗?有人可以解释一个线程一次释放堆栈对象上的锁吗?

Old*_*eon 5

一个synchronized方法只会阻止其他线程在执行时执行它.一旦它返回其他线程就可以(并且通常会立即)获得访问权限.

得到你的方案1 1 2 2 ...可能是:

  1. 线程1调用push(1)并被允许进入.
  2. 线程2调用push(1)并在线程1使用它时被阻止.
  3. 线程1退出push(1).
  4. 线程2获得访问push和推送1但同时线程1调用push(2).

结果1 1 2- 您可以清楚地看到它是如何继续的.

  • @javaTech - 没有合同说Java Threads应该公平.几乎任何订单都可能是您的代码的结果.1 1 2 2 ......非常有效. (7认同)