相同的线程能够在同一个对象上执行两个同步的方法

时间:2014-10-14 12:53:36

标签: java multithreading synchronization

正如我所知,只有一个线程可以在同一块上的同步方法上执行,但在生产者消费者问题中,我可以运行这两种方法。

示例代码

import java.util.concurrent.CountDownLatch;

public class VIV {

    public static void main(String[] args) throws Exception {
        Number no = new Number();

        //Same Object is passed
        Even ev = new Even(no, 10);
        Odd od = new Odd(no, 10);

        Thread oddThraed = new Thread(od,"ODD");
        oddThraed.start();

        Thread evenThraed = new Thread(ev,"Even");
        evenThraed.start();
    }
}

class Number {

    int no;
    boolean flag=false;

    public synchronized int getEvenNo() {
        System.out.println("In Even Method");
        // wait block so no other thread can enter on same object synchronized method
        try{
            wait();
        }catch (Exception e) {
            // TODO: handle exception
        }

        if(!flag) {
            try {
                Thread.sleep(1000);
            }catch (Exception e) {
                // TODO: handle exception
            }
        }   

        no=no+1;
        System.out.println(Thread.currentThread().getName()+":"+no);
        flag=false;
        notify();
        return no;
    }

    public synchronized int getOddNo() {
        System.out.println("In ODD Method");
        // wait block so no other thread can enter on same object synchronized method
        try{
            wait();
        }catch (Exception e) {
            // TODO: handle exception
        }

        if(flag) {
            try{
               wait();
            }catch (Exception e) {
                // TODO: handle exception
            }
        }   
        no = no+1;
        System.out.println(Thread.currentThread().getName()+":"+no);
        flag=true;
        notify();
        return no;
    }

}

class Even implements Runnable {
    Number num;
    int noOfTime;

    Even(Number no, int noOfTime) {
        this.num=no;
        this.noOfTime=noOfTime;
    }

    public void run() {
        for(int i=0;i<noOfTime;i++) {
            num.getEvenNo();
        }   
    }
}

class Odd  implements Runnable {

    Number num;
    int noOfTime;

    Odd(Number no, int noOfTime) {
        this.num=no;
        this.noOfTime=noOfTime;
    }   

    public void run() {
        for(int i=0;i<noOfTime;i++) {
            num.getOddNo();
        }   
    }
}

OutPut

  1. 在ODD方法
  2. 在Even Method中
  3. 因为只创建了一个Number对象并将其传递给在其两个不同的synchronized方法上调用的其他类。这两种方法都是在等待之后打印消息。

2 个答案:

答案 0 :(得分:4)

两种方法同时执行的原因是wait()方法释放锁。一旦synchronized方法调用wait(),就会返回锁定,另一个线程可以在同一个对象上调用另一个synchronized方法。不要以这种方式在wait()方法中调用synchronized

wait()电话也是您遇到死锁的原因。这就是发生的事情:

  1. odd方法获取锁定并开始执行。
  2. odd方法打印其第一条消息。
  3. odd方法调用wait(),释放锁并等待通知。
  4. even方法现在可以获取已释放的锁。
  5. even方法打印其第一条消息。
  6. even方法调用wait(),释放锁并等待通知。
  7. 到目前为止,您处于两个synchronized方法的中间(因为wait()释放锁定),并且您已经死锁(因为两种方法都在等待)。

    除非您确定自己需要的是什么,否则不要致电wait()。如果您的wait()只是为了让它等待查看同步是否可以被破坏,您可以尝试使用Thread.sleep(),这将暂停而不释放任何锁定。通常只需将相关方法或块声明为synchronized即可,而无需任何wait / notify

    (顺便说一句,拥有一个名为Number的类并不是一个好主意,因为这是一个标准的JDK类。它是DoubleInteger的超类,所以上。)

答案 1 :(得分:0)

我不知道你是否想要达到这种目的,如果你想打电话给 EVEN&amp; ODD或者,然后我修改了你的代码。看看下面的代码: -

public class VIV {

    public static void main(String[] args) throws Exception {

        TestNumber no = new TestNumber();
        // Same Object is passed
        Even ev = new Even(no, 10);
        Odd od = new Odd(no, 10);

        Thread oddThraed = new Thread(od, "ODD");
        oddThraed.start();

        Thread evenThraed = new Thread(ev, "Even");
        evenThraed.start();
    }
}

class TestNumber {

    int     no;
    boolean flag    = false;

    public synchronized int getEvenNo() {
        System.out.println("In Even Method");
        // wait block so no other thread can enter on same object synchronized
        // method

        no = no + 1;
        System.out.println(Thread.currentThread().getName() + ":" + no);
        flag = false;
        notify();

        try {
            wait();
        } catch (Exception e) {
            // TODO: handle exception
        }

        if (!flag) {
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        return no;
    }

    public synchronized int getOddNo() {
        System.out.println("In ODD Method");
        no = no + 1;
        System.out.println(Thread.currentThread().getName() + ":" + no);
        flag = true;
        notify();
        // wait block so no other thread can enter on same object synchronized
        // method
        try {
            wait();
        } catch (Exception e) {
            // TODO: handle exception
        }

        if (flag) {
            try {
                wait();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        return no;
    }
}

class Even implements Runnable {
    TestNumber  num;
    int     noOfTime;

    Even(TestNumber no, int noOfTime) {
        this.num = no;
        this.noOfTime = noOfTime;
    }

    public void run() {
        for (int i = 0; i < noOfTime; i++) {
            num.getEvenNo();
        }
    }
}

class Odd implements Runnable {

    TestNumber  num;
    int     noOfTime;

    Odd(TestNumber no, int noOfTime) {
        this.num = no;
        this.noOfTime = noOfTime;
    }

    public void run() {
        for (int i = 0; i < noOfTime; i++) {
            num.getOddNo();
        }
    }
}

注意:根据@ chiastic-security 数字的建议已在JDK中定义,我已在此代码中将其重命名为 TestNumber

输出

In ODD Method
ODD:1
In Even Method
Even:2
In ODD Method
ODD:3
In Even Method
Even:4
In ODD Method
ODD:5
In Even Method
Even:6
In ODD Method
ODD:7
In Even Method
Even:8
In ODD Method
ODD:9
In Even Method
Even:10
In ODD Method
ODD:11
In Even Method
Even:12
In ODD Method
ODD:13
In Even Method
Even:14
In ODD Method
ODD:15
In Even Method
Even:16
In ODD Method
ODD:17
In Even Method
Even:18
In ODD Method
ODD:19
In Even Method
Even:20