题目:使用两个线程交替打印1-10

依照题意:线程0打印1,线程1打印2,接着再次这样循环,一直到输出10为止。

我首先想到的是线程间的通信,首先让线程0执行,输出1,然后notify唤醒线程1,之后线程0立马wait释放锁。线程1拿到锁之后,输出2,同样,notify唤醒线程0,接着自己立马wait释放锁。

先写个示例代码:

package com.yang.testThreadPrint;

public class Main {

//输出的最大数字
private static final int MAX_NUM = 10;
//自增变量
private static volatile int i = 1;
//临界资源
private static final Object object = new Object();

public static void main(String[] args) {

Runnable r = new Runnable() {
@Override
public void run() {
synchronized (object) {
while (i <= MAX_NUM) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
try {
object.notify();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//防止有子线程被阻塞未被唤醒,导致主线程不退出
object.notify();
}
}
};

Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}

输出结果:

两个线程交替打印奇偶数_交替打印


顺便补充一些wait与notify的基础

wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行, 只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还 在别人手里,别人还没释放。如果notify/notifyAll方法后面的代码还有很多,需要这些代码执行完后才会释放锁),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

  • wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
  • wait()必须在同步块之内,且需要捕捉异常
  • 当前线程必须拥有此对象的锁,才能调用某个对象的wait()方法能让当前线程阻塞,(这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁)
  • 调用某个对象的notify()方法能够唤醒一个正在等待这个对象锁的线程,如果有多个线程都在等待这个对象锁,则只能唤醒其中一个线程
  • 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

关于wait()与sleep()的区别,可以参考我的另外一篇文章​​sleep与wait的区别​


上面是使用synchronized+wait+notify,下面使用ReentranLock+condition,本质上都是线程间通信

package com.yang.testThreadPrint;

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

public class MainByLock {

//输出的最大数字
private static final int MAX_NUM = 10;
//自增变量
private static volatile int i = 1;
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();


public static void main(String[] args) {

Runnable r = new Runnable() {
@Override
public void run() {
try {
lock.lock();
while (i <= MAX_NUM) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
condition.signal();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
condition.signal();
}
} finally {
lock.unlock();
}
}
};

Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}