java sleep、wait加锁对象与锁释放

public class use {
	public static void main(String[] args) {
		book b1 = new book();
		myThread1 t1 = new myThread1(b1);
		myThread2 t2 = new myThread2(b1);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}
}

// 线程类1
class myThread1 extends Thread {
	book b;
	public myThread1(book b) {
		super();
		this.b = b;
	}
	@Override
	public void run() {
		while(true){
			b.addbook();
			try {
				System.out.println("t1睡觉了哦");
				Thread.sleep(5000);
				System.out.println("t1醒了呐");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
}
//线程类2
class myThread2 extends Thread {
	book b;
	public myThread2(book b){
		this.b = b;
	}
	@Override
	public void run() {
		while(true){
			b.delbook();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

//资源类
class book{
	public int number;
	//增加数据
	public synchronized void addbook(){
		System.out.println(Thread.currentThread().getName()+"------"+(++number));;
	}
	//减少数据
	public synchronized void delbook(){
		System.out.println(Thread.currentThread().getName()+"------"+(--number));;
	}
	
}

上面这个程序,分别对增加书籍与减少书籍方法使用锁。它们使用的是book的内置锁。
在t1调用sleep之前与之后输出语句,这样,如果运行结果没有t2的运行输出就说明没有释放锁,
如果有输出就说明释放了锁。
在这里插入图片描述
这个结果很明显是释放了锁呀,为什么大家都说sleep不释放锁?
其实这混淆了一个概念:
锁是加在实例对象上的,不论是线程实例的sleep还是Object实例的wait,都指的是对象实例。
wait是所有实例都有的方法,sleep只能是线程实例拥有。

例中的myThread1的实例对象t1属于对象实例的特殊情况的线程实例
wait应用在Object对象上,那么线程实例对象也有wait

更改上面的程序:
在myThread2中添加t1实例,不断打印myThread1的实例t1的线程状态

package com.baidu.li;

public class use {
	public static void main(String[] args) {
		book b1 = new book();
		myThread1 t1 = new myThread1(b1);
		myThread2 t2 = new myThread2(b1,t1);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}
}

// 线程类1
class myThread1 extends Thread {
	book b;
	public myThread1(book b) {
		super();
		this.b = b;
	}
	@Override
	public void run() {
		while(true){
			b.addbook();
			try {
				System.out.println("t1睡觉了哦");
				Thread.sleep(50000);
				System.out.println("t1醒了呐");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
}
//线程类2
class myThread2 extends Thread {
	book b;
	myThread1 t1;
	public myThread2(book b,myThread1 t1){
		this.b = b;
		this.t1 = t1;
	}
	@Override
	public void run() {
		while(true){
			b.delbook();
			/*
			 * 如果t1线程处于sleep状态就调用t1对象实例的wait方法
			 * 因为wait方法必须要获得对象实例的锁才能成功运行
			 * 不然会抛出
			 * 获取不到对象锁异常IllegalMonitorStateException
			 */
			if(t1.getState()==State.TIMED_WAITING){
				try{
					t1.wait();
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

//资源类
class book{
	public int number;
	public synchronized void addbook(){
		System.out.println(Thread.currentThread().getName()+"------"+(++number));;
	}
	
	public synchronized void delbook(){
		System.out.println(Thread.currentThread().getName()+"------"+(--number));;
	}
	
}


在这里插入图片描述
可以看出t1的线程在调用sleep之后为TIMED_WAITING后,调用t1的wait方法抛出了获取不到对象锁错误,说明sleep没有释放t1的对象锁。

这里有一个小疑惑,找了很久都没有找到Object提供的锁状态函数,为什么不给提供呐?

以上两步分析了sleep不会释放线程自身的锁,看似sleep释放了它操作的对象book实例的对象锁,但是真的释放了吗?我们是在t1线程的run函数里面,add()函数之后,调用的t1的sleep。此时add函数执行完毕才会去调用sleep函数,自然是释放了book实例对象的对象锁。我们为了要验证它sleep之后会不会释放操作对象的对象锁,等到时间到了自动唤醒接着原来的位置执行,我们就需要在它持有操作数锁的过程中,让他sleep,即在加了同步的add函数中让线程sleep。

更改代码如下:

public class use {
	public static void main(String[] args) {
		book b1 = new book();
		myThread1 t1 = new myThread1(b1);
		myThread2 t2 = new myThread2(b1,t1);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}
}

// 线程类1
class myThread1 extends Thread {
	book b;
	public myThread1(book b) {
		super();
		this.b = b;
	}
	@Override
	public void run() {
		while(true){
			try {
				b.addbook();
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
		}
	}
}
//线程类2
class myThread2 extends Thread {
	book b;
	myThread1 t1;
	public myThread2(book b,myThread1 t1){
		this.b = b;
		this.t1 = t1;
	}
	@Override
	public void run() {
		while(true){
			b.delbook();
		}
	}
}

//资源类
class book{
	public int number;
	public synchronized void addbook() throws InterruptedException{
		System.out.println(Thread.currentThread().getName()+"------"+(++number));
		System.out.println(Thread.currentThread().getName()+"说完这句我就睡觉了哦");
		Thread.sleep(5000);
		System.out.println(Thread.currentThread().getName()+"我又醒来了");
	}
	
	public synchronized void delbook(){
		System.out.println(Thread.currentThread().getName()+"------"+(--number));
	}
	
}


在这里插入图片描述
在代码中,让运行add函数的线程即t1休眠5秒,同时没有让t2线程休眠,这样如果t1释放了锁,那么在它休眠期间,t2将获得book的实例对象对象锁,不断执行,那么在输出t1睡觉了与醒来了之间应该输出t2运行delbook的结果。
如果没有释放就说明它没有释放锁。如上图,我们可以看出,t1线程并没有释放锁
这说明,如果a线程调用了sleep方法不仅它自身的线程对象锁不释放,而且它所持有的其他对象的对象锁也不会释放。

/*....The thread  does not lose ownership of any monitors....*/
//这是sleep函数源码中的注释的一句话,这个线程不会释放它所持有的任何监视器(锁)。

上面的验证结论与源码注释一致。sleep是native(本地)方法。

而wait的作用对象是Object对象,它会释放自身的对象锁,那么它会释放它持有的操作对象的对象锁吗?
更改add()函数中的Thread.sleep(5000);Thread.currentThread().getName().wait();同时去掉myThread1中的while循环,让它执行一次。
即让t1在持有book的实例对象锁的时候,调用t1对象的wait,我们没有写唤醒t1的代码,且t1与t2时不同对象,t2的运行不依赖t1的对象锁。如果它不释放book实例对象的对象锁,那么t2将等待而没有输出。t1因为循环会再一次调用

public class use {
	public static void main(String[] args) {
		book b1 = new book();
		myThread1 t1 = new myThread1(b1);
		myThread2 t2 = new myThread2(b1, t1);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}
}

// 线程类1
class myThread1 extends Thread {
	book b;

	public myThread1(book b) {
		super();
		this.b = b;
	}

	@Override
	public void run() {
				try {
					b.addbook();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	}
}

// 线程类2
class myThread2 extends Thread {
	book b;
	myThread1 t1;

	public myThread2(book b, myThread1 t1) {
		this.b = b;
		this.t1 = t1;
	}

	@Override
	public void run() {
		while (true) {
			b.delbook();
		}
	}
}

// 资源类
class book {
	public int number;

	public synchronized void addbook() throws InterruptedException {
		System.out.println(Thread.currentThread().getName() + "------"
				+ (++number));
		System.out.println(Thread.currentThread().getName() + "说完这句我就wait了哦");
		Thread.currentThread().getName().wait();
	}

	public synchronized void delbook() {
		if (number >-10 && number < 10) {
			System.out.println(Thread.currentThread().getName() + "------"
					+ (--number));
		}

	}

}

在这里插入图片描述
运行结果中,t1抛出了异常,t2继续输出,说明释放了book的实例对象锁。
但是注意运行状态是红色,说明程序挂起了。t2执行完了肯定线程结束了,那么就是t1线程在wait状态,没有被唤醒仍旧在等待。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值