wait():
1.wait()会使线程状态发生变化(runnable-->waiting,waiting-->runnable)
2.等的是对像的等待集上(wait()是Object的一个方法,所以等在该对象的等待集上)
3.使用的时候必须加锁,等在哪个对象上,就对哪个对象加锁(wait()执行成功时会释放锁,醒来时会重新请求锁)
4.哪个线程调用wait(),哪个线程进入等待集
5.notify()只唤醒一个,但不保证是哪一个,但notifyAll()会唤醒所有对象
public class WaitDemo {
private static Object object=new Object();
public static class A extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println(i);
}
synchronized (object){
try {
//1.释放object中的锁
//2.把线程放到object对象的等待集中
//3.把线程状态变为waiting
//wait()执行后,锁会被释放
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=100;i<110;i++)
{
System.out.println(i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread a=new A();
a.start();
Scanner scanner=new Scanner(System.in);
scanner.nextLine();
//被唤醒后
//1.把A线程从等待集中取出
//2.把A线程变的状态变为runnable
//3.尝试重新抢object的锁
synchronized (object){
object.notify();
}
System.out.println("main已执行完毕");
}
}
示例:有两个线程,n的范围只能是【0,10】,一个线程负责n++,一个线程负责n--
public class Nwait {
private static Object o=new Object();
private static int n=0;
private static class Sub extends Thread{
@Override
public void run() {
while(true){
synchronized (o){
if(n==0){
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//因为没把锁释放,所以把notify()放到这里也是可以的
//o.notify();
n--;
System.out.println(getName()+":"+n);
o.notify();
}
}
}
}
private static class Add extends Thread{
@Override
public void run() {
while(true){
synchronized (o){
if(n==9){
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
n++;
System.out.println(getName()+":"+n);
o.notify();
}
}
}
}
public static void main(String[] args) {
Thread sub=new Sub();
Thread add=new Add();
sub.start();
add.start();
}
}
力扣1114(按序打印):
public class OneTwoThree {
private static class Foo {
private volatile int n = 0;
//当n不为0时,不释放CPU,导致n无法及时更新
public void oneVersion1() {
synchronized (this) {
if (n != 0) {
return;
}
System.out.println("one");
n = 1;
}
}
//减少了锁的开销
public void oneVersion2() {
if (n != 0) {
return;
}
System.out.println("one");
n = 1;
}
//当n不为0时,线程会释放CPU,但是该线程任然参与CPU的抢夺
public void oneVersion3() {
if (n != 0) {
//通过yield释放CPU,可以适当增加性能
Thread.yield();
return;
}
//两句话次序不能颠倒
System.out.println("one");
n = 1;
}
//当n不为0时,线程不在参与CPU的抢夺,提高了代码的速度
public void oneVersion4() throws InterruptedException {
if (n != 0) {
synchronized (this) {
this.wait();
}
}
//两句话顺序不能颠倒
// 极端情况下,n=1执行后,线程调度,
// 会导致n的值改变却没有打印“one”,下次直接打印“two”
System.out.println("one");
n = 1;
synchronized (this) {
this.notifyAll();
}
}
}
}
死锁:
当A线程获得了lockA,这时时间片到了,A线程被调度出去了,B线程进来了,B线程获得了lockB,等下次时间到了,不管A线程还是B线程都不可能获得另外一把锁,彼此都锁住了对方线程,这就叫死锁
sleep()与wait()的区别:
1.wait()之前需要请求锁,执行时会释放锁,等被唤醒时在重新请求锁。这个锁是wait对像上的monitor lock
2.sleep()是无视锁的存在,即之前请求的锁不会被释放,没有锁也不会请求
3.wait()是Object的普通方法
4.sleep()是Thread的静态方法
消费者生产者问题: