如何使Thread - notify()/ notifyAll()私有

时间:2015-04-15 15:35:28

标签: java multithreading

有一种方法可以阻止线程调用notify() / notifyAll()? 然后,就可以在课堂内拨打notify

一种notify方法私有。 (一种,我们知道,我们不能)

这里有一些代码,必须注意OtherThread synchronized中我想要阻止的内容:

public class MainThread {

    public static void main (String[] args) throws InterruptedException{
        Thread.currentThread().setName("Main Thread");
        X x = new X();
        x.start();

        OtherThread y = new OtherThread(x);
        y.start();


        synchronized (x){
            System.out.println(Thread.currentThread().getName()+" Waiting");
            x.wait();
        }
        System.out.println(Thread.currentThread().getName()+": Now I'm running");

    }

}

class X extends Thread{


    public void run(){
        // setting thread name
        Thread.currentThread().setName("X");


        try {
            Thread.sleep(1000*5); // 5 seconds here
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this){
            this.notify();// I want only notify/notifyAll inside X to be possible
            System.out.println("Notified from "+Thread.currentThread().getName()+" Thread");
        }

    }
}

class OtherThread extends Thread{
    Thread t;

    public OtherThread(Thread x){ // pass the X thread to this thread
        this.t = x;
    }

    public void run(){
        // setting thread name
        Thread.currentThread().setName("OtherThread");

        try {
            Thread.sleep(1000*1); // 1 second here
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (t){
            t.notify(); // prevent this. To can't call notify from outside class X.
            System.out.println("Notified from "+Thread.currentThread().getName()+" Thread");
        }
    }

}

4 个答案:

答案 0 :(得分:2)

嗯,答案是你做不到。我的意思是,您根本无法更改notify / wait可见性(所有对象都设置为公开)

但是,我认为可见性不适合您。您正在使用X的实例作为您正在等待/通知的监视器。问题在于,您正在将X线程共享给其他线程,原因还有其他原因。因此,每个人都可以进行等待/通知。

我建议使用另一个对象作为监视器(而不是X的实例)并仅在需要与之交互的对象之间共享该对象。类似的东西:

public class MainThread {

    public static void main (String[] args) throws InterruptedException{
        Thread.currentThread().setName("Main Thread");
        Object monitor = new Object();

        X x = new X(monitor);
        x.start();

        OtherThread y = new OtherThread(x);
        y.start();


        synchronized (monitor){
            System.out.println(Thread.currentThread().getName()+" Waiting");
            monitor.wait();
        }
        System.out.println(Thread.currentThread().getName()+": Now I'm running");

    }

}

class X extends Thread{

    private Object monitor;

    public X(Object monitor) {
      this.monitor = monitor;
    }

    public void run(){
        // setting thread name
        Thread.currentThread().setName("X");


        try {
            Thread.sleep(1000*5); // 5 seconds here
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (this.monitor){
            this.monitor.notify();// I want only notify/notifyAll inside X to be possible
            System.out.println("Notified from "+Thread.currentThread().getName()+" Thread");
        }

    }
}

class OtherThread extends Thread{
    Thread t;

    public OtherThread(Thread x){ // pass the X thread to this thread
        this.t = x;
    }

    public void run(){
        // setting thread name
        Thread.currentThread().setName("OtherThread");

        try {
            Thread.sleep(1000*1); // 1 second here
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (t){
            t.notify(); // this will work, but it wont do anything.
            System.out.println("Notified from "+Thread.currentThread().getName()+" Thread");
        }
    }

}

此外,只有一个加号,我建议你看看更高级的同步方法。您可以创建一个更强大,语义更清晰的Semaphore(或CountDownLatch),而不是仅仅共享一个Object来使用它(这就是我喜欢它们的方式)。

****编辑****

另外,一个小建议。 Thread.currentThread().setName("X")实际上可以通过this.setName("X")更改Thread,因为您的对象是线程并且知道自己(虽然您不能在主线程上执行此操作)。但是我建议完全删除它,因为class X extends Thread { public X() { super("X") } public void run(){ try { ... } } class OtherThread extends Thread{ Thread t; public OtherThread(Thread x){ // pass the X thread to this thread super("OtherThread"); this.t = x; } public void run(){ try { ... } } 类暴露了一个允许你事先设置该名称的构造函数,所以不用做你正在做的事情,你可以:

{{1}}

答案 1 :(得分:0)

您不能阻止任何代码调用notify,因为它是Object的公共方法,并且子类不能降低继承方法或字段的可见性。

答案 2 :(得分:0)

您可以简单地创建一个包含Thread成员字段的包装类,但不能提供对notify()&的访问权限。 notifyAll()方法......

public class MyThreadWrapper { 
    private final Thread myThread;     

    public MyThreadWrapper(Runnable r) {
        myThread = new Thread(r);
    }

    //notice we haven't expose notify/notifyAll...

}

现在你的主要用:创建线程:

MyThreadWrapper myLimitedThread = new MyThreadWrapper(someRunnable);

答案 3 :(得分:0)

等待并通知/ notifyAll属于Object类和公共方法,任何有权访问该对象的人都可以调用这些方法。

这里的关键点是访问对象,如果你只想让某个类有权访问某个对象并通知/ notifyAll,那么你需要将该对象封装到该类,不要将该对象返回到外部世界。

class X {
    private Object lock;

    public void someMethod() {
        //lock.wait();
        //lock.notify();
    }
}

不确定您要做什么,但是如果您尝试跨不同线程同步对共享对象的访问,则有许多可用的结构取决于具体问题。

  • 阻止队列
  • FutureTask 等