美文网首页
同步模式之顺序控制

同步模式之顺序控制

作者: 抬头挺胸才算活着 | 来源:发表于2020-03-16 22:01 被阅读0次
  1. 固定运行顺序
    比如,必须先 2 后 1 打印

1.1 wait notify 版

    // 用来同步的对象
    static Object obj = new Object();
    // t2 运行标记, 代表 t2 是否执行过
    static boolean t2runed = false;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (obj) {
                // 如果 t2 没有执行过
                while (!t2runed) {
                    try {
                        // t1 先等一会
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println(1);
        });
        Thread t2 = new Thread(() -> {
            System.out.println(2);
            synchronized (obj) {
                // 修改运行标记
                t2runed = true;
                // 通知 obj 上等待的线程(可能有多个,因此需要用 notifyAll)
                obj.notifyAll();
            }
        });
        t1.start();
        t2.start();
    }

1.2 Park Unpark 版

Thread t1 = new Thread(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
// 当没有『许可』时,当前线程暂停运行;有『许可』时,用掉这个『许可』,当前线程恢复运行
LockSupport.park();
System.out.println("1");
});
Thread t2 = new Thread(() -> {
System.out.println("2");
// 给线程 t1 发放『许可』(多次连续调用 unpark 只会发放一个『许可』)
LockSupport.unpark(t1);
});
t1.start();
t2.start();
  1. 交替输出
    线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现.
    class SyncWaitNotify {
        private int flag;
        private int loopNumber;
        public SyncWaitNotify(int flag, int loopNumber) {
            this.flag = flag;
            this.loopNumber = loopNumber;
        }
        public void print(int waitFlag, int nextFlag, String str) {
            for (int i = 0; i < loopNumber; i++) {
                synchronized (this) {
                    while (this.flag != waitFlag) {
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(str);
                    flag = nextFlag;
                    this.notifyAll();
                }
            }
        }
    }
SyncWaitNotify syncWaitNotify = new SyncWaitNotify(1, 5);
new Thread(() -> {
  syncWaitNotify.print(1, 2, "a");
}).start();
new Thread(() -> {
  syncWaitNotify.print(2, 3, "b");
}).start();
new Thread(() -> {
  syncWaitNotify.print(3, 1, "c");
}).start();

Lock条件变量版

    class AwaitSignal extends ReentrantLock {
        public void start(Condition first) {
            this.lock();

            try {
                log.debug("start");
                first.signal();
            } finally {
                this.unlock();
            }
        }
        public void print(String str, Condition current, Condition next) {
            for (int i = 0; i < loopNumber; i++) {
                this.lock();
                try {
                    current.await();
                    log.debug(str);
                    next.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    this.unlock();
                }
            }
        }
        // 循环次数
        private int loopNumber;
        public AwaitSignal(int loopNumber) {
            this.loopNumber = loopNumber;
        }
    }
AwaitSignal as = new AwaitSignal(5);
Condition aWaitSet = as.newCondition();
Condition bWaitSet = as.newCondition();
Condition cWaitSet = as.newCondition();
new Thread(() -> {
as.print("a", aWaitSet, bWaitSet);
}).start();
new Thread(() -> {
as.print("b", bWaitSet, cWaitSet);
}).start();
new Thread(() -> {
as.print("c", cWaitSet, aWaitSet);
}).start();
as.start(aWaitSet);

2.3 Park

class SyncPark {
private int loopNumber;
private Thread[] threads;
public SyncPark(int loopNumber) {
this.loopNumber = loopNumber;
}
public void setThreads(Thread... threads) {
this.threads = threads;
}
public void print(String str) {
for (int i = 0; i < loopNumber; i++) {
LockSupport.park();
System.out.print(str);
LockSupport.unpark(nextThread());
}
}
private Thread nextThread() {
Thread current = Thread.currentThread();
int index = 0;
for (int i = 0; i < threads.length; i++) {
if(threads[i] == current) {
index = i;
break;
}
}
if(index < threads.length - 1) {
return threads[index+1];
} else {
return threads[0];
}
}
public void start() {
for (Thread thread : threads) {
thread.start();
}
LockSupport.unpark(threads[0]);
}
}
SyncPark syncPark = new SyncPark(5);
Thread t1 = new Thread(() -> {
syncPark.print("a");
});
Thread t2 = new Thread(() -> {
syncPark.print("b");
});
Thread t3 = new Thread(() -> {
syncPark.print("c\n");
});
syncPark.setThreads(t1, t2, t3);
syncPark.start();

相关文章

  • 同步模式之顺序控制

    固定运行顺序比如,必须先 2 后 1 打印 1.1 wait notify 版 1.2 Park Unpark 版...

  • 多线程二

    GCD 栅栏函数 dispatch_barrier_async 控制任务执行顺序,同步 保证线程安全 栅栏函数只能...

  • GCD分析(下)

    栅栏函数的应用 栅栏函数 作用: 控制任务执行顺序,同步 dispatch_barrier_async 前面的任务...

  • Zookeeper 跨进程共享锁

    本地使用Zookeeper伪集群模式,同步锁控制多个进程的同步状态。 1、获取锁 2、释放锁 3、代码示例

  • GCD 底层源码分析(三)

    栅栏函数 栅栏函数最直接的作用就是控制任务的执行顺序,同步。 dispatch_barrier_async 前面的...

  • 微服务MySQL改造

    MySQL 主从复制之半同步模式MYSQL半同步概念:一般情况下Mysql默认复制模式为异步 异步复制模式 主服务...

  • Javascript异步回调

    同步模式与异步模式 Javascript语言执行环境是“单线程”,一次执行一个任务,并且按照顺序依次执行。但是遇到...

  • ASP.NET Core 多线程 异步编程

    同步异步编程 同步编程是对于单线程来说的,就像我们编写的控制台程序,以main方法为入口,顺序执行我们编写的代码。...

  • 单例的写法

    单例模式的创建方式; 同步锁 :NSLock @synchronized(self) {} 信号量控制并发:dis...

  • Android设计模式之——Builder模式之源码使用场景(二

    我的开源社区博客同步发布更新:Android设计模式之——Builder模式之源码使用场景(二)

网友评论

      本文标题:同步模式之顺序控制

      本文链接:https://www.haomeiwen.com/subject/ivooehtx.html