wait、notify、notifyAll介绍

wait:在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待
wait(long timeout): 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待
notify:唤醒在此对象监视器上等待的单个线程(如果导致死锁)
notifyAll:唤醒在此对象监视器上等待的所有线程

锁池和等待池

锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中
·
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中

notify和notifyAll的区别

  1. 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
  2. 当调用了wait,wait后的代码就不再执行,当被唤醒再次执行时,直接从wait下一行开始执行
  3. 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争

死锁的四个必要条件

互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
·
请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
·
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
·
环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

指定线程执行顺序三种方式

方法1:通过共享对象锁加上可见变量来实现

public class MyService {

    int num = 1;

    public synchronized void thread1() {

        while (num != 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num = 2;
        System.out.println("thread--1");
        notifyAll();

    }

    public synchronized void thread2() {
        while (num != 2) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num = 3;
        System.out.println("thread--2");
        notifyAll();
    }

    public synchronized void thread3() {
        System.out.println("--------thread3-------");

        while (num != 3) {
            try {
                System.out.println("--------wait-------");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num = 1;
        System.out.println("thread--3");
        notifyAll();
    }
}
public class Thread1 extends Thread {

    private MyService mService;

    public Thread1(MyService myService) {
        this.mService = myService;
    }

    @Override
    public void run() {
        super.run();
        mService.thread1();
    }
}

public class Thread2 extends Thread {

    private MyService mService;

    public Thread2(MyService myService) {
        this.mService = myService;
    }

    @Override
    public void run() {
        super.run();
        mService.thread2();
    }
}

public class Thread3 extends Thread {

    private MyService mService;

    public Thread3(MyService myService) {
        this.mService = myService;
    }

    @Override
    public void run() {
        super.run();
        mService.thread3();
    }
}

public class ThreadOrder {

    public static void main(String[] args) {
        MyService myService = new MyService();
        
        //线程开启随便,不影响打印结果
        Thread thread3 = new Thread3(myService);
        thread3.start();

        Thread thread1 = new Thread1(myService);
        thread1.start();

        Thread thread2 = new Thread2(myService);
       	thread2.start();
    }
}

打印结果

--------thread3-------
--------wait-------
thread--1
thread--2
thread--3

或者

--------thread3-------
--------wait-------
thread--1
--------wait-------
thread--2
thread--3

注意

  1. 由thread3只打印一次得出,当当前线程再次获取到对象锁时,不是从方法或者重新执行,而是从wait的下一行开始执行
  2. wait为什么有时候打印一次,有时候打印两次呢?因为wait是用一个while语句包裹的,当线程1执行notifyAll后,如果线程2正好获取到对象锁,则打印一次,如果线程3正好获取到对象锁,则while语句继续执行,则会再打印一次,然后继续进入wait状态,等线程2执行

方法2:通过线程执行Join()
join:等待该线程终止

public class Thread8 extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            sleep(2000);
            System.out.println("---thread8---");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class Thread9 extends Thread {
    private Thread mThread;

    public Thread9(Thread thread) {
        this.mThread = thread;
    }

    @Override
    public void run() {
        super.run();
        try {
            mThread.join();
            sleep(2000);
            System.out.println("---thread9---");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Thread10 extends Thread {
    private Thread mThread;

    public Thread10(Thread thread) {
        this.mThread = thread;
    }

    @Override
    public void run() {
        super.run();
        try {
            mThread.join();
            System.out.println("---thread10---");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadOrder {

    public static void main(String[] args) {
        Thread thread8 = new Thread8();
        Thread thread9 = new Thread9(thread8);
        Thread thread10 = new Thread10(thread9);
        //顺序无所谓
        thread10.start();
        thread8.start();
        thread9.start();
    }
}

打印结果

---thread8---
---thread9---
---thread10---

方法3:通过主线程Join()

public class ThreadOrder {
    public static void main(String[] args) {
        Thread thread5 = new Thread5();
        Thread thread6 = new Thread6();
        Thread thread7 = new Thread7();
        try {
        	//顺序必须是这样
            thread5.start();
            thread5.join();
            thread6.start();
            thread6.join();
            thread7.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class Thread5 extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("---thread5---");
        }
    }

    static class Thread6 extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("---thread6---");

        }
    }

    static class Thread7 extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("---thread7---");

        }
    }
}

wait notifyAll测试
public class TestWait {

    public static void main(String[] args) {
        MyService myService = new MyService();
        Thread thread1 = new Thread1(myService);
        Thread thread2 = new Thread2(myService);
        thread1.start();
        thread2.start();
    }

    static class MyService {
        int num = 1;

        public synchronized void thread1() {
            System.out.println("--------thread1-------");

            while (num != 11) {
                try {
                    System.out.println("--------wait-------");
                    wait();//会让代码1处代码进入等待状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("thread--1");
        }


        public synchronized void thread2(String a) {
            System.out.println(a);
            num = 11;
            notifyAll();
        }

        public void method(String a) {
            System.out.println(a);
        }
    }


    static class Thread1 extends Thread {
        private MyService mService;

        public Thread1(MyService myService) {
            this.mService = myService;
        }

        @Override
        public void run() {
            super.run();
            mService.thread1();

            try {
                //代码1处
                mService.thread2("---什么时候打印我呢---");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    static class Thread2 extends Thread {

        private MyService mService;

        public Thread2(MyService myService) {
            this.mService = myService;
        }

        @Override
        public void run() {
            super.run();
            try {
                //保证让线程1先执行
                sleep(2000);
                mService.thread2("---thread2---");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

打印结果

--------thread1-------
--------wait-------
---thread2---
thread--1
---什么时候打印我呢---

以上引用:https://blog.csdn.net/difffate/article/details/63684290

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值