Object中的线程等待和Condition

使用wait()notify()的前置条件

调用wait()和notify()的线程必须是已经获取了synchronized对象锁(注意这里是对象锁不是类锁也就是说被static标记的方法是不行的)的线程。否则将会抛出java.lang.IllegalMonitorStateException

wait方法会主动让出已经获取到的synchronized锁,使得当前线程阻塞。所以如果线程没有获取到synchronized锁就调用wait()或者notify()就会报错,另外调用wait()和notify()的对象必须要和synchronized

是同一个对象。

以下四种代码都是错误的。

public class Demo2 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo2 demo = new Demo2();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });
        t1.start();
    }

    public void testa(Object lock) {
        try {
            //错误的
            this.wait();
            System.out.println("aaaaaaaaaaaaaa");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }
}
View Code
public class Demo2 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo2 demo = new Demo2();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });
        t1.start();
    }

    public void testa(Object lock) {
        try {
            //错误的
            this.notify();
            System.out.println("aaaaaaaaaaaaaa");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
View Code
public class Demo2 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo2 demo = new Demo2();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });
        t1.start();
    }

    public void testa(Object lock) {
        synchronized (lock) {
            try {
                //调用wait的对象是this而synchronized当前是Object对象锁
                this.wait();
                System.out.println("aaaaaaaaaaaaaa");
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
}
View Code
public class Demo2 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo2 demo = new Demo2();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });
        t1.start();
    }

    public void testa(Object lock) {
        synchronized (lock) {
            try {
                //synchronized使用的是Object锁而调用notify()的是this对象。
                this.notify();
                System.out.println("aaaaaaaaaaaaaa");
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }
}
View Code

wait()

调用此方法将当前线程进入阻塞状态,并且让出锁,直到另一个线程调用该对象的notify()方法或notifyAll()方法。

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Demo1 demo1 = new Demo1();
        Thread t1 = new Thread(() -> {
            demo1.exc();
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            demo1.exc2();
        });
        t2.start();
    }

    public synchronized void exc() {
        try {
            wait();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("aaa");
    }

    public synchronized void exc2() {
        System.out.println("bbb");
    }
}
View Code

以上代码片段t1和t2两个线程都使用的是demo1这个对象的锁。t1执行后获取到了锁,然后调用wait()后自身便处于了阻塞状态,t2线程获得了demo1对象锁并执行结束。

在这段代码中t1不会只会一直阻塞因为没有线程使用demo1的notify(),t1线程也没有被中断。

wait(long timeout)

指定的时间后线程将重新恢复就绪状态,拥有争夺锁的权力。参数单位为毫秒。

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Demo1 demo1 = new Demo1();
        Thread t1 = new Thread(() -> {
            demo1.exc();
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            demo1.exc2();
        });
        t2.start();
    }

    public synchronized void exc() {
        try {
            wait(3000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("aaa");
    }

    public synchronized void exc2() {
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        System.out.println("bbb");
    }
}
View Code

以上代码片段t1线程执行后会阻塞直到3秒后将重新恢复就绪状态,但此时锁被t2获取正在执行,直到t2执行结束后释放锁,t1继续执行。

wait(long timeout,int nanos)

这个重载方法除了毫秒外还允许传递一个int类型的纳秒值,取值范围是0-999999。纳秒和毫秒的换算是1毫秒=1000000纳秒。也就是说第二个参数最多接近于1毫秒。

public class Demo1 {
    public static void main(String[] args) throws Exception {
        Demo1 demo1 = new Demo1();
        Thread t1 = new Thread(() -> {
            demo1.exc();
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            demo1.exc2();
        });
        //t2.start();
    }

    public synchronized void exc() {
        try {
            System.out.println(System.currentTimeMillis());
            wait(3000,999999);
            System.out.println(System.currentTimeMillis());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("aaa");
    }

    public synchronized void exc2() {
        System.out.println("bbb");
    }
}
View Code

以上代码片段只执行了t1,t1线程在阻塞前和阻塞后的时间差大概为3016毫秒。

wait释放的哪个锁?

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }

        t2.start();

    }

    public synchronized void testa(Object lock) {
        System.out.println("aaaaaaaaaaaaaa1");
        synchronized (lock) {
            System.out.println("aaaaaaaaaaaaaa2");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void testb(Object lock) {
        System.out.println("bbbbbbbbbbbbbbbbbbb1");
        synchronized (lock) {
            System.out.println("bbbbbbbbbbbbbbbbbbb2");
        }
    }
}
View Code

以上代码片段testa()和testb()两个方法上有synchronized方法内部还有synchronized (lock){}。在main()中线程1执行a方法线程2执行b方法。最终的执行结果是:

aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2
bbbbbbbbbbbbbbbbbbb1

出现这个结果的原因是线程1执行a方法时先拿到this锁也就是Demo对象的锁,又拿到了lock这个锁(也就是Object这个对象的锁)然后wait()执行后释放了this锁,为什么释放的是this锁?因为wait()默认使用的对象是this。也就是this.wait();

线程2执行b方法获取了this锁,但是无法拿到lock对象锁,所以进不去代码块。

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }

        t2.start();

    }

    public synchronized void testa(Object lock) {
        System.out.println("aaaaaaaaaaaaaa1");
        synchronized (lock) {
            System.out.println("aaaaaaaaaaaaaa2");
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void testb(Object lock) {
        System.out.println("bbbbbbbbbbbbbbbbbbb1");
        synchronized (lock) {
            System.out.println("bbbbbbbbbbbbbbbbbbb2");
        }
    }
}
View Code

将代码稍稍修改,wait()由lock对象调用。执行结果是:

aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2

结果不出意料,lock.wait()释放了lock这个对象锁。线程2执行b方法拿不到this锁第一层都进不去。

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
        }

        t2.start();

    }

    public synchronized void testa(Object lock) {
        System.out.println("aaaaaaaaaaaaaa1");
        synchronized (this) {
            System.out.println("aaaaaaaaaaaaaa2");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void testb(Object lock) {
        System.out.println("bbbbbbbbbbbbbbbbbbb1");
        synchronized (lock) {
            System.out.println("bbbbbbbbbbbbbbbbbbb2");
        }
    }
}
View Code

将a方法中synchronized代码块的锁修改为this。此时a方法中的两个锁都是this。执行wait()释放this锁。线程2执行b方法可以获取this锁,同时lock对象锁占用也可以获取所以打印结果是:

aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2
bbbbbbbbbbbbbbbbbbb1
bbbbbbbbbbbbbbbbbbb2

notify()

唤醒正在等待对象监控的单个线程。

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        Thread t3 = new Thread(() -> {
            demo.testc(lock);
        });

        t2.start();
        t1.start();
        try {
            Thread.sleep(1000);
        }catch (Exception e) {
        }    
        t3.start();
    }

    public synchronized void testa(Object lock) {
        try {
            this.wait();
            System.out.println("aaaaaaaaaaaaaa");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public synchronized void testb(Object lock) {
        try {
            this.wait();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public void testc(Object lock) {
        synchronized (this) {
            try {
                this.notify();
            } catch (Exception e) {
                System.out.println(e);
            }

        }

    }
}
View Code

以上代码片段线程1和线程2执行a,b方法。而a,b方法都调用了this.wait()也就是说t1和t2线程都是被this对象锁阻塞了。线程3调用this.notify()会唤醒t1,t2中的一个阻塞线程。

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        Thread t3 = new Thread(() -> {
            demo.testc(lock);
        });

        t2.start();
        t1.start();
        try {
            Thread.sleep(1000);
        }catch (Exception e) {
        }    
        t3.start();
    }

    public synchronized void testa(Object lock) {
        try {
            this.wait();
            System.out.println("aaaaaaaaaaaaaa");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public synchronized void testb(Object lock) {
        try {
            this.wait();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public void testc(Object lock) {
        synchronized (lock) {
            try {
                lock.notify();
            } catch (Exception e) {
                System.out.println(e);
            }

        }

    }
}
View Code

将c方法中的锁更改为lock对象,notify()方法也由lock对象调用则t1,t2两个线程都不会被唤醒。因为notify()唤醒的线程只能是被和自身同一个对象锁阻塞的线程。

另外如果c方法的synchronized是this锁而调用notify()的是其他对象则也会报错。

notifyAll()

唤醒正在等待对象监控的所有线程。

public class Demo1 {
    public static void main(String[] args) {
        Object lock = new Object();
        Demo1 demo = new Demo1();

        Thread t1 = new Thread(() -> {
            demo.testa(lock);
        });

        Thread t2 = new Thread(() -> {
            demo.testb(lock);
        });

        Thread t3 = new Thread(() -> {
            demo.testc(lock);
        });

        t2.start();
        t1.start();
        try {
            Thread.sleep(1000);
        }catch (Exception e) {
        }    
        t3.start();
    }

    public synchronized void testa(Object lock) {
        try {
            this.wait();
            System.out.println("aaaaaaaaaaaaaa");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public synchronized void testb(Object lock) {
        try {
            this.wait();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    public void testc(Object lock) {
        synchronized (this) {
            try {
                this.notifyAll();
            } catch (Exception e) {
                System.out.println(e);
            }

        }

    }
}
View Code

以上代码将notify()更换成了notifyAll()则t1,和t2线程都会被唤醒。

Condition

condition接口它的功能其实和Object中的wait()notify()方法的作用是一样的。wait()使线程进入阻塞状态notify()解除线程的阻塞状态它们要配合synchronized使用。

也就是说只有被synchronized锁住的代码块内才可以使用wait()和notify()。

condition接口提供了await();使用线程进入阻塞状态sigal()解除线程阻塞状态。则是配合Lock接口使用的。

Lock.newCondition()方法获取一个Condition接口的实现类。

await()signal()的前置条件

await()和signal()必须要在lock()方法后,并且调用await()signal()的Condition对象必须和lock()方法是同一组内的。也就是说一个Lock对象要和Condition对象是成对使用

的。这和wait()notify()方法必须和synchronized锁是同一个对象锁是一样的。

以下四种写法都是错误的。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    
    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(()->{
            demo.a();
        });
        t1.start();
    }

    public void a() {
        try {
            condition.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
View Code
public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    
    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(()->{
            demo.a();
        });
        t1.start();
    }

    public void a() {
        try {
            condition.signal();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
View Code
public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    
    ReentrantLock lock2 = new ReentrantLock();
    Condition condition2 = lock2.newCondition();
    
    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(()->{
            demo.a();
        });
        t1.start();
    }

    public void a() {
        try {
            lock.lock();
            condition2.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
View Code
public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    
    ReentrantLock lock2 = new ReentrantLock();
    Condition condition2 = lock2.newCondition();
    
    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(()->{
            demo.a();
        });
        t1.start();
    }

    public void a() {
        try {
            lock.lock();
            condition2.signal();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
View Code

await()

使当前线程阻塞直到中断或被signal()方法唤醒。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
    }

    public void a() {
        try {
            lock.lock();
            condition.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上代码执行结果是t1线程被阻塞不会执行输出,t2线程会正常结束。t1线程执行a()方法后获取lock锁然后await()会将当前线程阻塞并且释放lock锁。t2线程获取锁输出结果后释放锁,但t1线程始终无人唤醒。

await(timeout,TimeUnit)

这个重载方法给除了一个等待时间和时间单位。如果在指定时间结束后线程没有被signal()方法唤醒也没有中断则会自动被唤醒。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
    }

    public void a() {
        try {
            lock.lock();
            condition.await(3,TimeUnit.SECONDS);
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上方法t1线程阻塞后释放lock锁,t2线程获取锁在执行完毕后释放lock锁。t1线程在3秒后自动唤醒然后获取lock锁执行代码。

awaitNanos(timeout)

这个重载方法以纳秒为单位的时间单位。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
    }

    public void a() {
        try {
            lock.lock();
            condition.awaitNanos(3000000000L);
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上代码片段3000000000L纳秒也就是3秒它的执行效果和condition.await(3,TimeUnit.SECONDS)是相同的。

awaitUntil(Date)

这个重载方法接收一个Date时间,表示在指定的时间到达后自动唤醒线程。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
    }

    public void a() {
        try {
            lock.lock();
            SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date parse = sm.parse("2021-01-23 22:35:00");
            condition.awaitUntil(parse);
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上代码t2线程会在时间到达后获取锁并执行完毕。

awaitUninterruptibly()

以上4个使线程阻塞的方法如果在阻塞过程中线程被调用interrupt()则会接收到一个InterruptedException异常。而awaitUninterruptibly()阻塞方法被中断则不会接收到异常。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t1.interrupt();
    }

    public void a() {
        try {
            lock.lock();
            condition.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code
public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        t1.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t2.start();
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t1.interrupt();
    }

    public void a() {
        try {
            lock.lock();
            condition.awaitUninterruptibly();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            System.out.println("bbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上两个代码片段第一个会接收到InterruptedException异常第二个则不会。

signal

signal()唤醒一个被当前lock锁阻塞的线程。它从await()阻塞队列中获取阻塞时间最长的线程将其唤醒。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        Thread t3 = new Thread(() -> {
            demo.c();
        });
        t2.start();
        t1.start();
        
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t3.start();
    }

    public void a() {
        try {
            lock.lock();
            condition.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            condition.await();
            System.out.println("bbbbbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void c() {
        try {
            lock.lock();
            System.out.println("ccccccccccc");
            condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上代码片段t3线程执行后会释放阻塞队列中阻塞时间最长的线程也就是t2线程,t1线程不会被唤醒。

signalAll

signal()唤醒所有被当前lock锁阻塞的线程。

public class Demo2 {

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        Thread t1 = new Thread(() -> {
            demo.a();
        });
        Thread t2 = new Thread(() -> {
            demo.b();
        });
        Thread t3 = new Thread(() -> {
            demo.c();
        });
        t2.start();
        t1.start();
        
        try {
            Thread.sleep(1000 * 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        t3.start();
    }

    public void a() {
        try {
            lock.lock();
            condition.await();
            System.out.println("aaaaaaaaaaaa");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        try {
            lock.lock();
            condition.await();
            System.out.println("bbbbbbbbbbbbbbbbb");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void c() {
        try {
            lock.lock();
            System.out.println("ccccccccccc");
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
View Code

以上代码t3线程执行后会将t2,t1线程全部唤醒。

模拟生产者消费着案例

synchronized,wait,notifyAll实现

package com.datang.bingxiang;


public class Demo3 {

    int count = 0;
    int no = 0;

    public void produce() {
        synchronized (this) {
            while (count != 0) {
                try {
                    notifyAll();
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count++;
            no++;
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在生产" + no);
        }
    }

    public void consumer() {
        synchronized (this) {
            while (count == 0) {
                try {
                    notifyAll();
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count--;
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在消费" + no);
        }
    }

    public static void main(String[] args) {
        Demo3 demo = new Demo3();
        Thread t1 = new Thread(() -> {
            while (true) {
                demo.produce();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t2 = new Thread(() -> {
            while (true) {
                demo.produce();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t3 = new Thread(() -> {
            while (true) {
                demo.consumer();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t4 = new Thread(() -> {
            while (true) {
                demo.consumer();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
View Code

ReentrantLock,Condition实现

package com.datang.bingxiang;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo4 {
    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    int count = 0;
    int no = 0;

    public void produce() {
        try {
            lock.lock();
            while (count != 0) {
                try {
                    condition.signalAll();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count++;
            no++;
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在生产" + no);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }

    public void consumer() {
        try {
            lock.lock();
            while (count == 0) {
                try {
                    condition.signalAll();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count--;
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在消费" + no);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Demo4 demo = new Demo4();
        Thread t1 = new Thread(() -> {
            while (true) {
                demo.produce();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t2 = new Thread(() -> {
            while (true) {
                demo.produce();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t3 = new Thread(() -> {
            while (true) {
                demo.consumer();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t4 = new Thread(() -> {
            while (true) {
                demo.consumer();
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
View Code

 

posted @ 2021-01-23 23:11  顶风少年  阅读(195)  评论(0编辑  收藏  举报
返回顶部