启动a、b两个线程,由这两个线程打印出1到100共一百个数字。
要求:
两个线程交替打印,就是要两个线程之间进行同步,走走停停。线程的同步可以使用Object类自带的wait和notify(或者notifyAll)方法实现。
每个线程都是执行完一次打印之后,唤醒另外一个线程,然后自己进入等待状态。
需要注意的是:
(1)线程的启动顺序,需要先启动一个线程进入等待状态;另一个线程后启动直接执行,执行完唤醒等待线程,自己进入等待。
(2)线程何时退出,等打印了100之后,就不需要再等待了,而是退出。
public class PrintNum implements Runnable{
//是否现在先运行
private boolean runNow;
private Object lock;
private int num;
public PrintNum(boolean runNow, Object lock, int num) {
this.runNow = runNow;
this.lock = lock;
this.num = num;
}
@Override
public void run(){
synchronized(lock){
while(num <= 100) {
if (runNow) {
//第一次进来可以直接运行,但是循环第二次之后需要先等到唤醒才能运行
runNow = false;
} else {
//先等待
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(num);
num += 2;
//通知其他线程运行
lock.notify();
}
}
}
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new PrintNum(true, lock, 1));
Thread t2 = new Thread(new PrintNum(false, lock, 2));
//t2先运行,先进入等待状态
t2.start();
//t1直接运行,唤醒t2之后进入等待
t1.start();
}
}
wait()、notify()方法的相同点与区别:
相同点:
不同点:
一句话总结:wait使当前线程停止运行,而notify使停止的线程继续运行。它们俩搭配使用,就可以实现进程的通知、等待(或者叫做同步,或者进程的走走停停)。
使用wait、notify的一般格式:
// 线程1
//锁住对象
synchoronized(lockObj){
//当条件不满足时,线程等待
while(!condition) {
lockObj.wait();
}
// 被唤醒之后,且满足了条件,执行某些操作
doSomething();
}
//线程2
synchronized(lockObj){
doSomething();
// 唤醒等待在LockObj对象上面的一个线程;或者使用lockObj.notifyAll()唤醒所有等待在该对象上面的线程
lockObj.notify();
}
除了使用synchronized配合wait、notify方法实现进程的同步,还可以使用jdk提供的工具类来实现进程的通信。
Lock
Condition await、signal、signalAll
同时这些更加灵活,可以自定义唤醒不同的线程。
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// thread 1
lock.lock();
condition.await();
doSomething();
lock.unlock();
// thread 2
lock.lock();
doSomething();
condition.signal();
lock.unlock();
public class PrintNum {
private int n;
private Semaphore odd = new Semaphore(1);
private Semaphore even = new Semaphore(0);
public PrintNum(int n) {
this.n = n;
}
public void printOdd() {
for (int i=1; i<=n; i+=2) {
try {
odd.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
even.release();
}
}
public void printEven() {
for(int i=2; i<=n; i+=2) {
try {
even.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
odd.release();
}
}
public static void main(String[] args){
PrintNum printNum = new PrintNum(10);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> {
printNum.printOdd();
});
executorService.submit(() -> {
printNum.printEven();
});
executorService.shutdown();
}
}
package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
/**
* 测试三个线程轮流打印 1、2、3; 4、5、6; 7、8、9;
*
*/
private static void testThreeThreadPrint() {
Lock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
Condition c3 = lock.newCondition();
Wrapper wrapper = new Wrapper(1);
TestThread t1 = new TestThread(lock, c1, c2, wrapper);
TestThread t2 = new TestThread(lock, c2, c3, wrapper);
TestThread t3 = new TestThread(lock, c3, c1, wrapper);
t1.start();
t2.start();
t3.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
c1.signal();
lock.unlock();
}
public static void main(String[] args) {
testThreeThreadPrint();
}
}
class TestThread extends Thread{
Lock lock;
Condition awaitCondition;
Condition signalCondition;
Wrapper wrapper;
public TestThread(Lock lock, Condition awaitCondition, Condition signalCondition, Wrapper wrapper) {
this.lock = lock;
this.awaitCondition = awaitCondition;
this.signalCondition = signalCondition;
this.wrapper = wrapper;
}
@Override
public void run() {
while (wrapper.getNum() < 10) {
lock.lock();
try {
awaitCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (wrapper.getNum() < 10) {
System.out.println(wrapper.getNum());
wrapper.setNum(wrapper.getNum() + 1);
}
signalCondition.signal();
lock.unlock();
}
}
}
class Wrapper {
private int num;
public Wrapper(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}