两个线程交替打印1-100

线程之间的通信基本的三个方法:

  • wait():一旦执行该方法,当前线程就会堵塞状态,并释放同步监视器(锁)
  • notify():一旦执行该方法,就会唤醒被wait的一个线程,如果是多个,则唤醒优先级高的线程
  • notifyAll():一旦执行该方法,就会唤醒所有被wait的线程

1.使用 synchronized 和 wait notify 来实现两个线程交替打印

public class TestPrintNumber {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number,"线程1");
        Thread t2 = new Thread(number,"线程2");
        t1.start();
        t2.start();
    }
}

class Number implements Runnable{

    private int i = 0;

    @Override
    public void run() {
        while (true){
            synchronized (this) {
                notify();
                if(i < 100){
                    i++;
                    System.out.println(Thread.currentThread().getName()+"---"+i);
                }else{
                    break;
                }
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果:

线程1---1
线程2---2
线程1---3
线程2---4
线程1---5
线程2---6
..............
线程1---95
线程2---96
线程1---97
线程2---98
线程1---99
线程2---100
Process finished with exit code 0

这里需要注意:

  • wait(),notify(),notifyAll()三个方法必须使用在同步代码块或者同步方法中

我们再将线程类改成如下:


```java
class Number implements Runnable{

    private int i = 0;
    //注意这里使用object对象作为锁
    private Object object = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (object) {
                notify();
                if(i < 100){
                    i++;
                    System.out.println(Thread.currentThread().getName()+"---"+i);
                }else{
                    break;
                }
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果会报错,报错信息如下:
在这里插入图片描述
我们还要注意wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或者同步方法中的同步监视器(锁),在上面的例子,同步代码块的锁为object对象,而现在notify和wait方法的调用者是this,即Number对象的实例,我们需要改成object去调用notify()和wait()方法即可。

补充:sleep()和wait()的异同
相同点:执行这两个方法,都可以使调用线程进入堵塞状态。
不同点:

1.声明位置不一样,Thread类中声明sleep(),Object类中声明的wait()方法。
2.调用要求不一样,sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或者同步方法中。
3.当两个方法都在同步代码块或者同步方法中,sleep()不会释放锁,wait()会释放锁。

2.使用Lock和Condition实现
在Condition对象中,与wait() ,notify() ,notifyAll()方法分别对应的是await() , signal() ,signalAll()方法。Condition实例实质上被绑定到一个锁上。要为特定Lock实例获得Condition实例,使用其newCondition()方法。
将第一个Number类改成以下代码,也可以实现一样的结果。

class Number implements Runnable {

    private int i = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    @Override
    public void run() {
        while (true) {
            //加锁
            lock.lock();
            try {
                condition.signal();
                if (i < 100) {
                    i++;
              System.out.println(Thread.currentThread().getName() + "---" + i);
                } else {
                    break;
                }
                condition.await();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //解锁
                lock.unlock();

            }

        }
    }
}

这里注意下lock()和unlock()方法调用的位置
阿里巴巴开发手册中写明:

在使用阻塞等待获取锁的方式中,必须在try代码块之外,并且在加锁方法与try代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在finally中无法解锁。
说明一:如果在lock方法与try代码块之间的方法调用抛出异常,那么无法解锁,造成其它线程无法成功获取锁。
说明二:如果lock方法在try代码块之内,可能由于其它方法抛出异常,导致在finally代码块中,unlock对未加锁的对象解锁,它会调用AQS的tryRelease方法(取决于具体实现类),抛出IllegalMonitorStateException异常。
说明三:在Lock对象的lock方法实现中可能抛出unchecked异常,产生的后果与说明二相同。 java.concurrent.LockShouldWithTryFinallyRule.rule.desc

Positive example:

   Lock lock = new XxxLock();
    // ...
    lock.lock();
    try {
        doSomething();
        doOthers();
    } finally {
        lock.unlock();
    }

Negative example:

  Lock lock = new XxxLock();
    // ...
    try {
        // If an exception is thrown here, the finally block is executed directly
        doSomething();
        // The finally block executes regardless of whether the lock is successful or not
        lock.lock();
        doOthers();

    } finally {
        lock.unlock();
    }
  • 18
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值