介绍
谈这些方法一定与多线程有关,但是不一定与synchronized有关。
sleep与yield##
这两个都是线程类的静态方法,调用的目的是释放当前cpu的使用权,但是有不同的地方。
- 使用sleep的时候如果使用了synchronized,那么不会释放对对象的控制权
- sleep可以控制时间,但是yield不能
- yield释放CPU使用权,只有同等级别或者更高级别的线程能拿到cpu的使用权
以上3点有点难以理解,下面我举一个简单的例子来区分一下。
一个自助蛋糕店,门口有很多人排队,蛋糕店同时只能容纳一个人在里面随便吃东西,门口排队的人被随机选中进来吃随机的时间。sleep就像一个正在里面吃的人,要去上厕所(设置了一个固定的时间),上完厕所后继续在门口排队。如果sleep外面加了synchronized,那么就是他上厕所的时候标记了一下他正在吃的蛋糕(这需要额外支付费用,另外的人进来不能吃),而yield则是自己吃累了,想出去歇歇,但是不能设定休息时间。但是只能与他有相同身份或者比他身份更加高级的人才能进来享受蛋糕。
##wait notify##
wait notify notifyall是必须在synchronized块中使用的,是为了解决多线程使用共享资源问题。这三个都是object的三个方法。wait是让当前线程处于等待状态,等待notify方法被调用后继续执行。
举例一个场景:
一把斧头 可以被多个人使用,如果使用坏了,那么有一个人可以进行维修。使用者是多个线程,维修者也是一个线程。
因为在synchronized中,所以同一时间,只有一个使用者可以拿到斧头的使用权。是其中的是一个使用者拿到斧头的使用权的时候,先检查斧头能否使用,如果可以使用,则一直使用,跳出synchronized后。另一个使用者可以有机会使用。一旦维修者拿到斧头的使用权,维修者判断斧头能否使用,发现斧头是可以使用的,那么就调用wait方法(让出斧头的使用权)。那些使用者一直在使用,但是有一个使用者一不小心把斧头使用坏了,则调用notify方法。这个时候维修者拿到使用权,并且检查斧头坏了,进行维修。维修之后调用notify方法。
就这样多线程的配合,让斧头一直正常工作下去。
package aaa;
public class Futou {
public boolean isUsed = true;
public void use() {
try {
while(true) {
synchronized(this) {
if(this.isUsed == true) {
System.out.println(Thread.currentThread().getId() + "开始干活");
Thread.sleep(1000);
if(System.currentTimeMillis() % 5 == 0) {
this.isUsed = false;
System.out.println(Thread.currentThread().getId() + "斧头坏了");
this.notifyAll();
}
}else {
this.wait();
}
}
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void repair() {
try {
while(true) {
if(this.isUsed == false) {
System.out.println(Thread.currentThread().getId() + "开始维修");
Thread.sleep(1000);
this.isUsed = true;
this.notifyAll();
}else {
this.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Futou ft = new Futou();
//启动10个使用的线程
for(int i = 0; i < 10;i++) {
new Thread() {
public void run() {
ft.use();
}
}.start();
}
//启动一个维修的线程
new Thread() {
public void run() {
ft.repair();
}
}.start();
}
}