呀?这就是锁(二)?

java常用锁

CountDownLatch(倒数计数器,门栓)

package AboutSysn;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
	
	public static void main(String[] args) {
	
		CountDownLatch cdl = new CountDownLatch(2); //添加两道栅栏,
		for(int i = 0;i<5;i++) {
			new Thread(()->{
				System.out.println(Thread.currentThread().getName()+"-----1");
				if(cdl.getCount()>0) {
					cdl.countDown();	//释放一层栅栏
				}
				try {
					cdl.await();	//等待栅栏全部释放后,才可以继续执行
					
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-----2");
			}).start();;
		}
		
		
	}
}

总结:

CountDownLatch 维护了一个int变量,当这个变量等于0是,所有等待这个变量的线程开始运行。等待的过程使用的是CAS,这个最后写到AQS时详说,现在只需要明白只要线程执行了 cdl.await,其背后的意义就是告诉这个线程你要等待 cdl 的 count 的值变成0。

CyclicBarrier(同步屏障)

package AboutSysn;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {

	public static void main(String[] args) {
		CyclicBarrier cb = new CyclicBarrier(2);
		List<Thread> threads = new ArrayList<Thread>();
		for(int i = 0;i<6;i++) {
		Thread t = new Thread(()->{
				
				System.out.println(Thread.currentThread().getName()+"到达");
				try {
					cb.await(); //等待其他线程到达
					System.out.println(Thread.currentThread().getName()+"执行了");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			});
		threads.add(t);
		}
		
		threads.forEach(o->{
			o.start();
			try {
				Thread.sleep(1000);
				System.out.println(o.getName()+"开始执行");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		});
		
	}
}
//结果 这个结果还能证明指令重排序,优秀!!!!
Thread-0到达
Thread-0开始执行
Thread-1到达
Thread-1执行了
Thread-0执行了
Thread-1开始执行
Thread-2到达
Thread-2开始执行
Thread-3到达
Thread-3执行了
Thread-2执行了
Thread-3开始执行
Thread-4到达
Thread-4开始执行
Thread-5到达
Thread-5执行了
Thread-4执行了
Thread-5开始执行

总结:

我们可以使用CyclicBarrier使需要彼此配合的线程协同工作,例如ThreadA的计算需要ThreadB的部分结果就可以这样使用。相当于增强的CountDownLatch

Phaser

package AboutSysn;

import java.util.concurrent.Phaser;

public class PhaserDemo {

	static Phaser p = new MyPhaser();
	//看电影
	static class MyPhaser extends Phaser{
		protected boolean onAdvance(int phase, int registeredParties) {
			
			System.out.println(phase+"--"+registeredParties);
			switch (phase) {
			case 0:
				//这里进行所有线程都要执行的任务
				System.out.println("所有人进场");
				return  false;
			case 1:
				System.out.println("观看电影");
				return false;
			case 2:
				//这里执行只有管理员线程要做的任务
				System.out.println("除管理员,其他人离场");
				return true;
			default:
				return true;
			}
		}
		
	}
	public static void main(String[] args) {
		p.bulkRegister(5); //p会拦截5个线程然后放行
		Runnable r = new Runnable() {
			void m1() {
				System.out.println("m1");
				p.arriveAndAwaitAdvance();
			}
			void m2() {
				System.out.println("m2");
				p.arriveAndAwaitAdvance();
			}
			void m3() {
				System.out.println("m3");
				String name = Thread.currentThread().getName();
				if(!name.equals("Thread-4")) {
					p.arriveAndDeregister(); //游客线程去掉
				}else {
					p.arriveAndAwaitAdvance(); //管理员线程保留
				}
			}
			@Override
			public void run() {
				// TODO Auto-generated method stub
				m1(); //第一次栅栏拦截,
				m2(); //第二次栅栏拦截
				m3(); //第三次栅栏拦截
			}
		};
		
		for(int i=0;i<5;i++)
		{
			new Thread(r).start();;
		}
	}
}
//结果
m1
m1
m1
m1
m1
0--5
所有人进场
m2
m2
m2
m2
m2
1--5
观看电影
m3
m3
m3
m3
m3
2--1
除管理员,其他人离场

总结:

Phaser其本质和另外两种没有什么区别,相当于增强了CyclicBarrier,可以在过程中对拦截线程数量进行动态的调整,可以让一部分线程做一个特殊的任务。

posted @ 2021-05-11 11:15  二五树  阅读(33)  评论(0编辑  收藏  举报