标签:cut 循环 int 消费 rac 进入 tac bottom ++
实现一个容器,线程2添加10个元素,线程1实时监督线程2,当容器中元素个数达到5个时,给出提示并结束。
这题本身并不是很难,类似生产者、消费者问题,线程1等待线程2添加元素达到5个,线程1消费这个事件。
因此可以想到的是利用生产者消费者范式来解决。
我主要用生产者消费者范式和JUC中各个常用组件来解决这个问题,熟悉下各个组件使用方法。
为了便于测试,这里建立了一个T1_Supervice_T2抽象类,提供两个模板方法,子类实现并用作t1, t2 线程的运行方法。T1_Supervice_T2_Test用来测试各个类的方法,整体结构如下:
T1_Supervice_T2抽象父类如下:
/**
* t2中添加十个元素,t1监督t2,t2添加了5个元素时给出通知
*/
public abstract class T1_Supervice_T2 {
public List<Integer> list = new ArrayList<>();
public Thread t1;
public Thread t2;
public T1_Supervice_T2(){
t1 = new Thread(()->run1());
t2 = new Thread(()->run2());
}
public void execute(){
t1.start();
t2.start();
}
public abstract void run1();
public abstract void run2();
}
测试类如下:
public class T1_Supervice_T2_Test {
public static void main(String[] args) {
// T1_Supervice_T2 test = new T1_Supervice_T2_Synchronized();
// T1_Supervice_T2 test = new T1_Supervice_T2_ReentrantLock();
// T1_Supervice_T2 test = new T1_Supervice_T2_CountDownLatch();
// T1_Supervice_T2 test = new T1_Supervice_T2_CycliBarrier();
// T1_Supervice_T2 test = new T1_Supervice_T2_Semaphore();
T1_Supervice_T2 test = new T1_Supervice_T2_LockSupport();
test.execute();
}
}
第1、2种方法是利用生产者消费者范式来写,范式如下:
等待方(消费者):
获得对象锁
条件不满足,则等待
条件满足,则执行
通知方(生产者):
获得对象锁
改变条件
通知在等待对象上的线程
注意:wait和notify必须要用在synchronized中,在外面会报错
public class T1_Supervice_T2_Synchronized extends T1_Supervice_T2 {
private Object lock = new Object();
@Override
public void run1() {
synchronized (lock){
while (list.size() != 5){
try {
lock.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("---------------list has 5 elements!---------------");
lock.notify();
}
}
}
@Override
public void run2() {
synchronized (lock){
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i+1) + "th element");
list.add(i);
if(list.size() == 5){
lock.notify();
try {
lock.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
}
注意: await方法和signal方法得在lock中间。并要显示的解锁
这里用两个条件,逻辑更加清晰一点
public class T1_Supervice_T2_ReentrantLock extends T1_Supervice_T2 {
private ReentrantLock lock = new ReentrantLock();
private Condition turn_t1 = lock.newCondition();
private Condition turn_t2 = lock.newCondition();
@Override
public void run1() {
try {
lock.lock();
while (list.size() != 5)
turn_t1.await();
System.out.println("---------------list has 5 elements!---------------");
turn_t2.signal();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
@Override
public void run2() {
try {
lock.lock();
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i + 1) + "th element");
list.add(i);
if (list.size() == 5) {
turn_t1.signal();
turn_t2.await();
}
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
CountDownLatch是一个门栓,到达某个一定数量后,就允许线程继续执行下去,但每次只能设置一次,因此在t2 线程中有一个再一次的赋值
调用:await和countDown方法
public class T1_Supervice_T2_CountDownLatch extends T1_Supervice_T2 {
private CountDownLatch latch = new CountDownLatch(1);
@Override
public void run1() {
if(list.size() != 5){
try {
latch.await();
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("---------------list has 5 elements!---------------");
latch.countDown();
}
@Override
public void run2() {
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i+1) + "th element");
list.add(i);
if(list.size() == 5){
latch.countDown();
latch = new CountDownLatch(1);
try {
latch.await();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
}
CycliBarrier是循环栅栏,同时到达一定数量后,允许所有线程继续执行,同时恢复到设置的初始值。
只需要调用await方法即可
public class T1_Supervice_T2_CycliBarrier extends T1_Supervice_T2{
CyclicBarrier barrier = new CyclicBarrier(2);
@Override
public void run1() {
if(list.size() != 5){
try {
barrier.await();
System.out.println("---------------list has 5 elements!---------------");
barrier.await();
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public void run2() {
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i+1) + "th element");
list.add(i);
if(list.size() == 5){
try {
barrier.await();
barrier.await();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
Semaphore是信号量,用来限流的,同时允许n 个线程运行,主要方法acquire用来请求获取使用权,为0时阻塞。release是释放。
这里实际上没有用到Semaphore,主要是join启到了调整运行顺序。
public class T1_Supervice_T2_Semaphore extends T1_Supervice_T2{
private Semaphore semaphore = new Semaphore(1);
@Override
public void execute(){
t2.start();
}
@Override
public void run1() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("---------------list has 5 elements!---------------");
semaphore.release();
}
@Override
public void run2() {
try {
//semaphore.acquire();
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i + 1) + "th element");
list.add(i);
if (list.size() == 5) {
semaphore.release();
t1.start();
t1.join();
semaphore.acquire();
}
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
LockSupport是JUC中一个支持性包。park可以使线程进入waiting状态。unpark则对应线程退出waiting状态。这个不需要在锁下使用,比较灵活,且代码简洁。
public class T1_Supervice_T2_LockSupport extends T1_Supervice_T2 {
@Override
public void run1() {
if(list.size() != 5){
LockSupport.park();
}
System.out.println("---------------list has 5 elements!---------------");
LockSupport.unpark(t2);
}
@Override
public void run2() {
for (int i = 0; i < 10; i++) {
System.out.println("list adds " + (i+1) + "th element");
list.add(i);
if(list.size() == 5){
LockSupport.unpark(t1);
LockSupport.park();
}
}
}
}
标签:cut 循环 int 消费 rac 进入 tac bottom ++
原文地址:https://www.cnblogs.com/muche-moqi/p/13168651.html