为什么wait()和notify()方法一定要搭配synchronized关键字才可以使用
因为如果不加synchronized关键字,会导致程序代码在多线程下,代码执行顺序混乱的问题。
如在A1B2C3交替输出的场景下: 如果不加synchronized关键字,两个线程同时执行,假如都执行到LOCK.wait()方法,就永远不会有人来唤醒它们了。
wait()方法
线程直接释放对象的锁,进入了等待队列,状态从RUNNING转变为WAITING,等待notify的唤醒.
notify()方法
唤醒在等待队列的线程,将在等待队列的线程移入同步队列,状态从WAITING等待变为BLOCKING阻塞,等到该线程的同步代码块执行完毕,会释放锁,然后同步队列的线程会争夺LOCK对象的monitor。
代码
奇偶交替输出
public class OddEvenPrinter extends Thread{
private static Object LOCK = new Object();
private static int end;
private static volatile int num;
OddEvenPrinter(int start,int end){
this.num = start;
this.end = end;
}
@Override
public void run(){
synchronized (LOCK){
while(num <= end){
LOCK.notify();
System.out.println(Thread.currentThread().getName() + "的输出为:" + num);
num++;
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
LOCK.notifyAll();
}
}
public static void main(String[] args) {
Thread threadA = new OddEvenPrinter(1,10);
threadA.setName("OddThread");
Thread threadB = new OddEvenPrinter(1,10);
threadB.setName("EvenThread");
threadA.start();
threadB.start();
}
}
123123循环输出
public class OneTwoThreePrinter implements Runnable{
private static volatile int num;
private static int times;
private int targetNum;
private static Object LOCK = new Object();
public OneTwoThreePrinter(int num,int times,int targetNum){
this.num = num;
this.times = times;
this.targetNum = targetNum;
}
@Override
public void run() {
synchronized (LOCK){
for(int i = 0 ; i < times ; i++){
while(num % 3 != targetNum){
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "输出的num值为: "+(targetNum+1));
num++;
LOCK.notifyAll();
}
}
}
public static void main(String[] args) {
OneTwoThreePrinter oneTwoThreePrinter0 = new OneTwoThreePrinter(0, 4,0);
OneTwoThreePrinter oneTwoThreePrinter1 = new OneTwoThreePrinter(0, 4,1);
OneTwoThreePrinter oneTwoThreePrinter2 = new OneTwoThreePrinter(0, 4,2);
new Thread(oneTwoThreePrinter0,"Thread1").start();
new Thread(oneTwoThreePrinter1,"Thread2").start();
new Thread(oneTwoThreePrinter2,"Thread3").start();
}
A1B2C3交替输出
public class LetterNumberPrinter implements Runnable{
private static Object LOCK = new Object();
@Override
public void run() {
synchronized (LOCK){
for(int i = 0 ; i < 26 ; i++){
if(Thread.currentThread().getName() == "NumberThread"){
LOCK.notify();
int num = i+1;
System.out.println(num);
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if(Thread.currentThread().getName() == "LetterThread"){
LOCK.notify();
char c = (char) ((char) 'A'+i);
System.out.println(c);
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//防止还有子线程阻塞在代码块中
LOCK.notifyAll();
}
}
public static void main(String[] args) {
LetterNumberPrinter thread1 = new LetterNumberPrinter();
LetterNumberPrinter thread2 = new LetterNumberPrinter();
new Thread(thread1,"LetterThread").start();
new Thread(thread1,"NumberThread").start();
}
}