java并发编程——同步模式之顺序控制

同步模式之顺序控制

比如,两个线程同时启动,必须先 打印2打印1

wait notify 版

package cn.itcast.test;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test25")
public class Test25 {
    
    
    static final Object lock = new Object();
    // 表示 t2 是否运行过
    static boolean t2runned = false;

    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(() -> {
    
    
            synchronized (lock) {
    
    
                while (!t2runned) {
    
    
                    try {
    
    
                        lock.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                log.debug("1");
            }
        }, "t1");


        Thread t2 = new Thread(() -> {
    
    
            synchronized (lock) {
    
    
                log.debug("2");
                t2runned = true;
                lock.notify();
            }
        }, "t2");

        t1.start();
        t2.start();
    }
}

测试

12:25:12.967 c.Test25 [t2] - 2
12:25:12.970 c.Test25 [t1] - 1

也可以使用ReentrantLockawaitsignal来实现。

park Unpark版

可以看到,实现上很麻烦:

  • 首先,需要保证先 wait 再 notify,否则 wait 线程永远得不到唤醒。因此使用了『运行标记』来判断该不该wait
  • 第二,如果有些干扰线程错误地 notify 了 wait 线程,条件不满足时还要重新等待,使用了 while 循环来解决此问题
  • 最后,唤醒对象上的 wait 线程需要使用 notifyAll,因为『同步对象』上的等待线程可能不止一个

可以使用 LockSupport 类的 park 和 unpark 来简化上面的题目:

@Slf4j(topic = "c.Test26")
public class Test26 {
    
    
    public static void main(String[] args) {
    
    

        Thread t1 = new Thread(() -> {
    
    
            LockSupport.park();
            log.debug("1");
        }, "t1");
        t1.start();

        new Thread(() -> {
    
    
            log.debug("2");
            LockSupport.unpark(t1);
        },"t2").start();
    }
}

同步模式之交替输出

线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现

wait notify 版

@Slf4j(topic = "c.Test27")
public class Test27 {
    
    
    public static void main(String[] args) {
    
    
        WaitNotify wn = new WaitNotify(1, 5);
        new Thread(() -> {
    
    
            wn.print("a", 1, 2);
        }).start();
        new Thread(() -> {
    
    
            wn.print("b", 2, 3);
        }).start();
        new Thread(() -> {
    
    
            wn.print("c", 3, 1);
        }).start();
    }
}

/*
输出内容       等待标记     下一个标记
   a           1             2
   b           2             3
   c           3             1
 */
class WaitNotify {
    
    
    // 打印               a           1             2
    public void print(String str, int waitFlag, int nextFlag) {
    
    
        for (int i = 0; i < loopNumber; i++) {
    
    
            synchronized (this) {
    
    
                while(flag != waitFlag) {
    
    
                    try {
    
    
                        this.wait();
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                System.out.print(str);
                flag = nextFlag;
                this.notifyAll();
            }
        }
    }

    // 等待标记
    private int flag; // 2
    // 循环次数
    private int loopNumber;

    //构造方法
    public WaitNotify(int flag, int loopNumber) {
    
    
        this.flag = flag;
        this.loopNumber = loopNumber;
    }
}

输出

abcabcabcabcabc

Lock条件变量版

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

public class Test30 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        AwaitSignal awaitSignal = new AwaitSignal(5);
        Condition a = awaitSignal.newCondition();
        Condition b = awaitSignal.newCondition();
        Condition c = awaitSignal.newCondition();
        new Thread(() -> {
    
    
            awaitSignal.print("a", a, b);
        }).start();
        new Thread(() -> {
    
    
            awaitSignal.print("b", b, c);
        }).start();
        new Thread(() -> {
    
    
            awaitSignal.print("c", c, a);
        }).start();

        Thread.sleep(1000);
        awaitSignal.lock();
        try {
    
    
            System.out.println("开始...");
            a.signal();
        } finally {
    
    
            awaitSignal.unlock();
        }

    }
}

class AwaitSignal extends ReentrantLock{
    
    
    private int loopNumber;

    public AwaitSignal(int loopNumber) {
    
    
        this.loopNumber = loopNumber;
    }
    //            参数1 打印内容, 参数2 进入哪一间休息室, 参数3 下一间休息室
    public void print(String str, Condition current, Condition next) {
    
    
        for (int i = 0; i < loopNumber; i++) {
    
    
            lock();
            try {
    
    
                //使当前线程等待,直到发出信号或中断。与此条件相关联的锁被原子释放,
                //  当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生四种情况之一
                current.await();
                //打印
                System.out.print(str);
                next.signal();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                unlock();
            }
        }
    }
}

输出

abcabcabcabcabc

park Unpark版

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.LockSupport;

@Slf4j(topic = "c.Test31")
public class Test31 {
    
    

    static Thread t1;
    static Thread t2;
    static Thread t3;
    public static void main(String[] args) {
    
    
        ParkUnpark pu = new ParkUnpark(5);
        t1 = new Thread(() -> {
    
    
            pu.print("a", t2);
        });
        t2 = new Thread(() -> {
    
    
            pu.print("b", t3);
        });
        t3 = new Thread(() -> {
    
    
            pu.print("c", t1);
        });
        t1.start();
        t2.start();
        t3.start();

        LockSupport.unpark(t1);
    }
}

class ParkUnpark {
    
    
    public void print(String str, Thread next) {
    
    
        for (int i = 0; i < loopNumber; i++) {
    
    
            LockSupport.park();
            System.out.print(str);
            LockSupport.unpark(next);
        }
    }

    private int loopNumber;

    public ParkUnpark(int loopNumber) {
    
    
        this.loopNumber = loopNumber;
    }
}

输出

abcabcabcabcabc

猜你喜欢

转载自blog.csdn.net/e891377/article/details/109158511