Java 无法预测给定的程序

Java 无法预测给定的程序,java,multithreading,timer,synchronized,Java,Multithreading,Timer,Synchronized,上述计划中存在三个疑问: 1我想从这个程序得到的是,当线程t1启动时,转到synchronized方法synchronized timermethod将锁定对象ts1,并应将其锁定,直到计时器对象违反条件为止。因此,线程t2将无法获得对共享资源ts1的常规访问,并且无法取得进展,并将陷入饥饿状态。但这并没有发生。使用Timer类不可能吗?我是新手 2当线程t1启动时,它转到synchronized method synchronized Timermethod,对象ts1将被锁定。在计时器对象被

上述计划中存在三个疑问:

1我想从这个程序得到的是,当线程t1启动时,转到synchronized方法synchronized timermethod将锁定对象ts1,并应将其锁定,直到计时器对象违反条件为止。因此,线程t2将无法获得对共享资源ts1的常规访问,并且无法取得进展,并将陷入饥饿状态。但这并没有发生。使用Timer类不可能吗?我是新手

2当线程t1启动时,它转到synchronized method synchronized Timermethod,对象ts1将被锁定。在计时器对象被调度之前,对象ts1不会被释放,直到条件被破坏。但发生的事情是线程t1定时器对象第一次按计划启动时,只有线程t2进入同步方法SynchronizedTimeMethod。对象ts1是否由于计时器运行方法而被释放

3另外,当两个线程都违反了条件时,任务不会被取消,特别是程序死锁,或者我认为它会进入死锁。为什么?

我重写了我的代码如下:

public class ThreadStarvation implements Runnable{
         long startTime=System.currentTimeMillis();
         Timer t;

    class RunnerTask extends TimerTask  {

      public void run(){
        if((System.currentTimeMillis()- startTime)< 100000){
           System.out.println(Thread.currentThread().getName()+": in timer  task run() method"+" : "+Calendar.getInstance().getTime());

       }
    else
        t.cancel();
      }
   }

public synchronized void synchronizedTimerMethod(){

try{
    Thread.sleep(1000);
    t=new Timer();
    t.schedule(new RunnerTask(), 0, 2000);
}
   catch(InterruptedException ie){}
}

public void run(){
    synchronizedTimerMethod();

}

public static void main(String[] args) {

            ThreadStarvation ts1=new ThreadStarvation();
            Thread t1=new Thread(ts1);
            Thread t2=new Thread(ts1);
            t1.start();
            t2.start();
  }
}

现在我只想停止这项任务。为此,我将计时器对象作为最终对象。然后,任务似乎也不会取消。是否需要更多的修改?请提供帮助。

1如果您想强制执行t1在t2之前进入的事实,那么您不能依靠计时器或时间来确保这种任意交错。您应该将其重写为具有屏障条件(仅允许t1首先进入)的监视器。然后使t1永远不要释放锁以使t2饥饿,即防止同步方法终止

什么是监视器?如何创建监视器? 在并发性中,它是一种用于同步程序并使其更可预测的构造,如图所示,t1在t2之前。在此上下文中,同步基于满足的某些条件/状态。这些条件充当屏障,阻止或允许线程执行。这是非常有用的,因为我们可以使用这些障碍不仅使我们的程序模式可预测,而且还允许我们保证并发中某些理想的属性,即公平性、避免死锁等。因此监视器的重要性

在Java中,我们可以通过定义一个类来创建监视器,该类将屏障条件定义为私有变量。然后,我们只允许通过先测试条件是否满足的同步方法更改这些变量

下面是一个简单的示例,以简化代码为基础进行说明:

   public class ThreadStarvation implements Runnable{
       long startTime=System.currentTimeMillis();
       final Timer t=new Timer;

class RunnerTask extends TimerTask  {

  public void run(){
    if((System.currentTimeMillis()- startTime)< 100000){
       System.out.println(Thread.currentThread().getName()+": in timer  task run() method"+" : "+Calendar.getInstance().getTime());

   }
else
    t.cancel();
  }
}

public synchronized void synchronizedTimerMethod(){

try{
  Thread.sleep(1000);
  t.schedule(new RunnerTask(), 0, 2000);
}
  catch(InterruptedException ie){}
}

public void run(){
    synchronizedTimerMethod();

 }

public static void main(String[] args) {

        ThreadStarvation ts1=new ThreadStarvation();
        Thread t1=new Thread(ts1);
        Thread t2=new Thread(ts1);
        t1.start();
        t2.start();
  }
}
注意:这只是一个简单的示例,并不理想,也就是说,您不应该定义一个实现Runnable的监视器。您可以阅读有关监视器的更多信息。此外,我建议通过以下我也使用

2见immibis的详细回答

3从以下地址:

在对计时器对象的最后一次实时引用消失并且所有未完成的任务都已完成执行后,计时器的任务执行线程将正常终止,并接受垃圾收集。但是,这可能需要任意长的时间。默认情况下,任务执行线程不作为守护进程线程运行,因此它能够防止应用程序终止。如果调用方希望快速终止计时器的任务执行线程,则调用方应调用计时器的cancel方法

这和你想象的不一样。synchronized方法等待一秒钟,然后安排RunnerTask每两秒钟发生一次,然后返回。请注意,它不会等待RunnerTask运行。ts1仅在SynchronizedTimeMethod返回之前锁定,即1秒


如果在100秒后违反该条件,您只会因为错误而取消一个计时器。请注意,SynchronizedTimeMethod将t设置为新计时器,并且只有一个变量t。在调度第一个任务之后,t是一个计时器-称它为计时器1。在安排第二个任务之后,t是一个不同的计时器-称它为计时器2。然后,当100秒结束时,两个任务都取消t,这将取消计时器2两次。

这是否意味着由于计时器类的原因,计划方法对象ts1被释放?否,当synchronizedTimerMethod返回时,ts1被释放。这就是同步方法的工作原理-调用该方法时对象被锁定,返回时对象被释放。@因此,如果您永远不希望释放锁,因此无法释放另一个锁,请阻止同步方法终止/返回。请看我的解释。计时器t是类变量,所以两个线程共享相同的引用。将创建计时器1和计时器2对象,因为schedule方法将为每个线程创建RunnerTask的新对象。因此,当引用相同时,它必须取消这两个任务。@Nizam它是ThreadFairation的类变量,而不是RunnerTask。只有一个线程饥饿的实例。首先,我只想澄清一下,假设在synchronized方法SynchronizedTimeMethod af中
ter sleep我只写for循环然后同步方法只会在for循环完成后返回?目前,由于睡眠后计时器类的存在,它在睡眠后返回。我说的对吗?其次,我阅读java文档,但若我将Timer对象作为类对象,那个么每个线程只会创建一个Timer-0对象,那个么它将能够取消任务?或者有什么办法吗?@Nizam sleep不会释放锁,请参见。线程在运行方法结束时终止,在这种情况下是synchronizedTimerMethod终止时。@Nizam您需要调用t.cancel以正常终止计时器上的任务。这取决于您想做什么,但我认为您应该在线程即将终止时这样做。请更新您的Q,我可以帮助您进一步阐述。正如immibis所指出的,您不断创建计时器的新实例,但不要这样做。相反,您应该实例化t,并在声明它时将其设置为final,即final Timer t=new Timer;我的问题与你的计划无关。这与我最初的计划有关。请回答我关于我的程序的问题。@Nizam,它正在返回,因为在睡眠后,它正在创建一个新的计时器并计划一个新的RunnerTask,该任务开始独立执行。但对于您的线程,它会继续执行,因此会从synchronizedTimerMethod返回,然后synchronizedTimerMethod从run返回,从而终止该线程。
public class ExampleMonitor implements Runnable{
    // Condition for our barrier, note it is private
    private boolean t1Entered = false;

    public synchronized void synchronizedTimerMethod(){
        // Test the barrier (check if conditions hold)
        while (!t1Entered && !Thread.currentThread().getName().equals("t1")) { 
            try {
                // Did not pass barrier so wait and release lock
                wait();
            } catch (Exception e) {
                // Handle
            }
        }
        // Thread passed barrier and has acquired the lock and can do what it wants

        // Update condition so now anyone can enter/pass the barrier
        t1Entered = true;

        // If this method never terminates then no other thread can enter because lock is never released
        long enterTime = System.currentTimeMillis();
        while (true) {
            System.out.println(Thread.currentThread().getName());

            // Let's allow the method to return and thus release the lock after fixed amount of time
            // We can then see that threads other than t1 can now acquire the lock
            if (System.currentTimeMillis() - enterTime > 5000) {
                break;
            }
        }
        // Notify/wake up any waiting threads
        this.notifyAll();
    }

    public void run(){
        synchronizedTimerMethod();
        // Thread will now terminate
    }

    public static void main(String[] args) throws InterruptedException {
        ExampleMonitor ts1 = new ExampleMonitor();

        Thread t1=new Thread(ts1);
        t1.setName("t1");

        Thread t2=new Thread(ts1);
        t2.setName("t2");

        t2.start();
        // To illustrate how Monitors can be used to ensure 
        //  ordering despite the order threads start in
        Thread.sleep(2000);
        t1.start();
    }
}
public synchronized void synchronizedTimerMethod(){

try{
    Thread.sleep(1000);
    t=new Timer();
    t.schedule(new RunnerTask(), 0, 2000);
}
   catch(InterruptedException ie){}
}