问题描述
- 关于java sychronized锁代码块对该对象的其它sychonized方法是否有影响的问题。
-
代码是书上例子,我简化了,启用线程ob1后,通过主线程调用sychonized方法mysuspend()和myresume()来控制ob1线程的等待与重启。线程从15开始倒数,0.5秒个,主线程在1秒时候暂停文字提示,再过1秒重启线程。例子中的sychonized代码块仅包含wait()判定部分,输出与预期一样,倒数到14的时候中断,之后又恢复。但是当我将sychonized代码块前移,包含至 Thread.sleep(500)之前的时候,暂停时间常常之后到13时候,当sychonized代码块前移包含整个循环语句的时候,倒数代码段根本就停不下来,结束的时候主线程才调用了下mysuspend()挂起方法,就好像整个
ob1对象被锁住似的,所以请问,sychonized代码块锁住的地方和mysuspend()挂起方法是分别加锁,双方互相独立ob1可以同时进行两个部分,为什么后两种情况明显感到ob1.mysuspend()被锁住动不了的呢?public class NewThread implements Runnable{
String name; Thread t; static boolean suspendFlag; NewThread(String threadname) { name=threadname; t=new Thread(this,name); System.out.println("New thread:"+t); suspendFlag=false; t.start(); } public void run() { try { for(int i=15;i>0;i--) { System.out.println(name+":"+i); Thread.sleep(500); synchronized(this){while(suspendFlag){this.wait();}} } } }catch(InterruptedException e){} System.out.println(name+" exiting."); } synchronized void mysuspend(){suspendFlag=true;} synchronized void myresume(){suspendFlag=false;notify();}
}
public static void main(String[] args) {
NewThread ob1=new NewThread("One");
NewThread ob2=new NewThread("Two");
try{
Thread.sleep(1000);ob1.mysuspend(); System.out.println("Suspending thread One"); Thread.sleep(1000); ob1.myresume(); System.out.println("Resuming thread One");
}catch(InterruptedException e){}
解决方案
sychonized方法是不会影响其它的sychonized方法,一人sychonized上锁了,另一个sychonized方法只要没上锁就可以访问
解决方案二:
synchronized的参数就是监视器对象,只要监视器对象不同(即锁住的对象不同),即使是同一个对象的不同synchronized代码块之间是没有影响的。
你的代码中线程的run方法中使用到的是synchronized(this)就是当前线程对象,而静态方法的synchronized上的监视器对象是整个类的class类型信息,是不同的监视器对象,所以不会相互影响的。
运行了你的代码,你的run方法中使用的synchronized(this)是当前对象,而while(suspendFlag)条件变量又是静态全局的,所以当你将线程one先挂起后该标识为true,此时线程two执行到这行语句后的this.wait()就会将自己挂起,然后main函数正常resume了线程one,并且唤醒了自己。但是线程two没有被唤醒。所以最后的结果是线程one正常退出,而线程two就被挂起了,这个程序一直处于无法结束的状态。
Object的wait和notify是条件队列,只能唤醒和挂起在当前对象this上的线程,你的两个线程one和two在执行run方法时都有各自的this对象,都是在各自的this锁上的wait和notify,线程one正常退出是因为先wait后又notify,而线程two只wait挂起了,没有人来唤醒它就永远挂起了。
解决方案三:
补充一点:如果要让线程two正常结束则需要调用resume唤醒该线程,在最后执行一次ob2.myresume();它会将flag为false并且notify唤醒自己,程序就能正常结束了。