读写锁
应用场景,读写日志等,写日志是原子性的,但是读取日志不分先后顺序,所以需要锁住写线程,一个一个的执行完成后,再任意的运行读线程
public class MyReentrantReadWriteLock {
Object data = null;
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void write(Object data){
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "正在写入数据:" + data);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
} finally {
writeLock.unlock();
}
}
public Object read(){
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "正在读取数据:" + data);
} finally {
readLock.unlock();
}
return data;
}
}
public class Test {
public static void main(String[] args) {
MyReentrantReadWriteLock readWrite = new MyReentrantReadWriteLock();
new Thread(()->{
readWrite.write("停,还没放学呢。。。");
}).start();
for (int i = 0; i < 50; i++) {
new Thread(()->{
readWrite.read();
}).start();
}
new Thread(()->{
readWrite.write("放学。。恰饭");
}).start();
}
}
减少计数器
类似于上自习,人走完了,才有班长关教室。new CountDownLatch(10);锁10个线程,超了就无法锁住,执行一次线程计数器就减少一次。会阻塞主线程
public class StudyCountDownLatch {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(10);
System.out.println("保安同志🐉负责关门");
Random r = new Random();
for (int i = 0; i < 10; i++) {
new Thread(()->{
int nextInt = r.nextInt(4);
try {
TimeUnit.SECONDS.sleep(nextInt);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"离开了房间。。。");
long count = countDownLatch.getCount();
System.out.println("count = " + count);
countDownLatch.countDown();
},"同事小"+i).start();
}
int time = r.nextInt(10);
try {
Thread.sleep(1000 * time);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("宝安同志离开房间,把门锁死🔒");
}
}
循环栅栏
类似于集齐七龙珠,缺一不可。new CyclicBarrier(int parites,Runnable runnable),该方法有rest方法可以重置计数器。所有线程会统一阻塞,直到计数器加起来的个数达到要求,就会执行new CyclicBarrier的run方法。计数器加起来的个数没有达到要求就会一直阻塞,直到达到要求,可以用来处理异常
public class MyCyclicBarrier {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, ()->{System.out.println("*****集齐7颗龙珠就可以召唤神龙");}) ;
for (int i = 0; i < 7; i++) {
int num = i+1;
new Thread(()->{
Random r = new Random();
int time = r.nextInt(10);
try {
Thread.sleep(1000*time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"收集到第"+num+"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
System.out.println("主线程跑完了");
}
}
信号灯
类似于抢车位,或者直接点限流,谁先进来谁先用
public class MySemaphore {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 6; i++) {
int num = i+1;
new Thread(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+num+"号车进入车位");
Random r = new Random();
int time = r.nextInt(10);
try {
Thread.sleep(1000 * time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+num+"号车离开车位");
semaphore.release();
}).start();
}
System.out.println("================");
}
}