多线程协作——对象变量阻塞(wait/notify)
设想这样一个场景,当有线程通过条件判断发现库存不足时就不会继续执行代码;那么该线程就会进入阻塞状态,随之而来其他线程就一样进入阻塞;直到库存达到要求,所有线程唤醒,怎么样去实现这个呢???
在java中每个对象都一个wait方法,该方法就是将当前线程加入到对象的阻塞队列中
原理:阻塞信息保存在对象的等待队列中,可以利用notify()、notifyAll()来打破阻塞!
操作:先加锁,后阻塞等待(利用对象阻塞线程,则必须让该线程要加锁,因为这个加入等待池的过程是非线程安全的:)
提示:注意,wait方法阻塞后则进入已经完成会释放锁,其他的线程仍然可以进入这个验证流程决定是否进入阻塞!
public void produce(int num) {
synchronized (list) {
//生产计划值>库存最大值
while (list.size() + num > MAX_SIZE) {
System.out.println("库存上限暂时无法生产");
try {
list.wait();【利用对象加锁】
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < num; i++) {
list.add(new Object());
}
list.notifyAll();【利用对象解锁】
}
}
多线程协作——线程变量阻塞(join)
如何让某个线程等待另外一个线程执行完才执行呢?那就是用join方法,该方法同样会把当前线程加入到另外一个线程的等待池,当线程执行完后就唤醒
Thread download=new Thread(){
public void run(){
for(int i=1;i<=100;i++){
try {
Thread.sleep(50);
System.out.println("正在下载图片:"+i+"%");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread show =new Thread(){
public void run(){
for(int i=1;i<=100;i++){
try {
download.join();//将自己的线程的阻塞打破,放到另外线程的变量中,当另外线程死亡时则它才启动
Thread.sleep(50);
System.out.println("正在显示图片:"+i+"%");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("图片已经显示完成");
}
};
download.start();
show.start();
Ps:可以利用strat来控制,启动放在程序最后一行代码
多线程协作——线程次数控制(Semaphore)
如何实现线程访问量的控制,如果对达到指定数量就进入阻塞,答案是用aqs的共享模式;
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(3);//共享锁为的限制为3
try {
semaphore.acquire();//尝试获取共享锁,+1;失败自旋后进入阻塞
System.out.println("执行业务");
semaphore.release();//取消自己的共享锁,-1
}catch (InterruptedException e){
e.printStackTrace();
System.out.println("被中断了");
return;
}
}
多线程协作——末尾线程控制(countDownLatch/CyclicBarrier)
当全部线程执行完后,再执行某个线程;这种数字级别的控制如何实现?
/**
* @countDownLatch
* 1、其他线程利用数字减少
2、主线程一开始就会阻塞住
*/
CountDownLatch latch=new CountDownLatch(3);
ExecutorService service=Executors.newFixedThreadPool(5);
service.submit(()->{
latch.countDown();
});
service.submit(()->{
latch.countDown();
});
service.submit(()->{
latch.countDown();
});
latch.await();
System.out.println("游戏加载完成");
/**
* @CyclicBarrier
* 1、创建需指定数量;
* 2、其他线程利用await语法来减少数量后回调一个函数
*/
CyclicBarrier barrier=new CyclicBarrier(3,()->{
System.out.println("游戏加载完成");
});
ExecutorService service=Executors.newFixedThreadPool(5);
service.submit(()->{
barrier.await();
});
service.submit(()->{
barrier.await();
});
service.submit(()->{
barrier.await();
});
多线程协作——条件队列控制(Semaphore)
类似于等待通知,wait/notify;但是这是基于java内部实现的,另外一个是基于jvm实现的;
public class DataBase {
private List<String> dataRow;
private ReentrantLock lock;
private Condition conditionWrite;
private Condition conditionRead;
private volatile int writeQueueLength;
public DataBase() {
/**
* @创建锁
* 并利用锁生成条件队列,队列中就是一堆阻塞线程;利用通知——等待模式进行线程阻塞和唤醒类似于wait和notfily
* writeQueueLength是实时得获取最新得写队列得数量,如果这个时候写锁存在,那么读锁就只能进入等待队列
*/
this.lock = new ReentrantLock();
this.conditionRead=lock.newCondition();
this.conditionWrite=lock.newCondition();
this.writeQueueLength=lock.getWaitQueueLength(conditionWrite);
/**
* @创建初始化数据
*/
dataRow=new ArrayList<String>();
dataRow.add("1");
dataRow.add("2");
dataRow.add("3");
dataRow.add("4");
dataRow.add("5");
dataRow.add("6");
dataRow.add("8");
}
/**
* @读操作
*/
public void select() throws Exception{
if(writeQueueLength>0){//写锁存在,读锁进入等待队列
conditionRead.await();
}
System.out.println("开始读取数据");
}
/**
* @写操作
*/
public void update() throws Exception{
boolean lockStatus = lock.tryLock();
if(!lockStatus){
conditionWrite.await();
}
System.out.println("正在插入数据");
Thread.sleep(1000);
System.out.println("插入成功");
conditionRead.signalAll();//所有读得数据唤醒
conditionWrite.signal();//唤醒写锁一个继续插
}
}
JVM并发编程专题章节:
多线程管理
多线程框架
多线程测试GodSchool
致力于简洁的知识工程,输出高质量的知识产出,我们一起努力
博主私人微信:supperlzf