6.3 生产者-消费者案例【新方式】
案例:一个初始值为0的变量,两个线程交替操作,一个加一,一个减一,来5轮
class SahreData{ private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); // 加法 public void increament(){ lock.lock{ try{ //1.判断 while(number != 0){ condition.await(); } //2.干活 number++; System.out.println(Thread.currentThread().getName()+ number); //3.通知唤醒 condition.signalAll(); }catch(...){ }finally{ lock.unlock(); } } } // 减法 public void decreament(){ lock.lock{ try{ //1.判断 while(number == 0){ condition.await(); } //2.干活 number--; System.out.println(Thread.currentThread().getName()+ number); //3.通知唤醒 condition.signalAll(); }catch(...){ }finally{ lock.unlock(); } } } } public class ProdConsumer{ public static void main(String[] args){ ShareData shareData = new ShareData(); new Thread(()->{ for(int i = 1;i<=5;i++){ shareData.increament(); } },"A").start(); new Thread(()->{ for(int i = 1;i<=5;i++){ shareData.decreament(); } },"B").start(); } }
6.4 虚假唤醒
防止虚假唤醒 一定要用while 不要用if
6.3 中的代码换成If,多添加几个线程就会出现问题!
会出现结果 1 2 -1 0等等,并没有控制住结果。
七、Synchrinized与Lock的区别
1.前者JVM层面,是Java的关键字,后者是API层面,java5以后的出现的。
2. synchronized不可以中断
3. Reentranrlock可以中断,设置超时,或者中断方法
4.synchronized默认非公平锁
5.Reentranrlock可以分组唤醒,精确唤醒
6.synchronized要么随即唤醒一个,要么唤醒全部notify() notifyAll()
实现案例:
多线程之间要按照顺序调用,实现A-B-C三个线程启动:
AA打印5次,BB打印10次,CC打印15次
然后
AA打印5次,BB打印10次,CC打印15次
…
循环10次
7.1 打印案例【新的Lock版本】
class ShareResource{ private int number = 1;//A1 B2 C3 private Lock lock = new ReentrantLock(); private Condition c1 = new lock.newCondition(); private Condition c2 = new lock.newCondition(); private Condition c3 = new lock.newCondition(); public void prints5(){ lock.lock(); try{ //1.判断 while(number != 1){ c1.await(); } //2.干活 for(int i = 1;i<=5;i++){ System.out.println(Thread.currentThread().getName()+"\t"+number); } //3.通知2 number = 2; c2.signal(); }catch(){}finally{ lock.unlock(); } } public void prints10(){ lock.lock(); try{ //1.判断 while(number != 2){ c2.await(); } //2.干活 for(int i = 1;i<=10;i++){ System.out.println(Thread.currentThread().getName()+"\t"+number); } //3.通知2 number = 3; c3.signal(); }catch(){}finally{ lock.unlock(); } } public void prints15(){ lock.lock(); try{ //1.判断 while(number != 3){ c3.await(); } //2.干活 for(int i = 1;i<=10;i++){ System.out.println(Thread.currentThread().getName()+"\t"+number); } //3.通知2 number = 1; c1.signal(); }catch(){}finally{ lock.unlock(); } } } public class SyncAndReentrantLockDemo{ ShareSource shareSource = new ShareSource(); new Thread(()->{ for(int i=0;i<=10;i++){ shareSource.prints5(); } },"A").start(); new Thread(()->{ for(int i=0;i<=10;i++){ shareSource.prints10(); } },"B").start(); new Thread(()->{ for(int i=0;i<=10;i++){ shareSource.prints15(); } },"C").start(); }
7.2 生产消费案例【阻塞队列版本】高并发
class MyResource{ private volatile boolean FLAG = true;//默认开启,生产+消费 private AtomicInteger atomicInteger = new AtomicInteger(); BlockingQueue<String> blockingQueue = null; public MyResource(BlockingQueue<String> blockingQueue){ this.blockingQueue = blockingQueue; System.out.println(blockingQueue.getClass().getName()); } public void myProd(){ String data = null; boolean retValue; while(FLAG){ data = atomInteger.incrementAndGet()+""; retValue = blockingQueue.offer(data,2L,TimeUnit.SECONDS); if(retValue){ System.out.println(Thread.currentThread().getName()+"\t 插入队列"+data+"成功"); }else{ System.out.println(Thread.currentThread().getName()+"\t 插入队列"+data+"失败"); } TimeUint.SECONDS.sleep(1); } System.out.println(Thread.currentThread().getName()+"\t 生产叫停,false 生产结束"); } public void MyConsumer(){ String result = null; while(FLAG){ result = blockingQueue.poll(2L,TimeUnit.SECONDS); if(null == result || result.equalsIngoreCase("")){ FLAG = false; System.out.println(Thread.currentThread().getName()+"\t 超过2S没有消费,消费退出"); return; } System.out.println(Thread.currentThread().getName()+"\t 消费队列"+result+"成功"); } } public void stop(){ this.FLAG = fasle; } } public class ProdConsumer_BlockQueueDemo{ public static void main(String[] args){ MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10)); new Thread(()->{ System.out.println(Thread.currentThread().getName()+ "\t 生产线成启动"); myResource.myProd(); },"Prod").start(); new Thread(()->{ System.out.println(Thread.currentThread().getName()+ "\t 消费线成启动"); myResource.myConsumer(); },"Consumer").start(); //暂停一会 try{TimeUnit.SECONDS.sleep(5);catchh(...){}} System.out.println("5S结束,大老板叫停,活动结束"); myResource.stop(); } }
八、线程池
8.1 Runnable与 Callable
class MyThread implements Runnable{ @Override public void run(){ } } class MyThread2 implements Callable<Integer>{ @Override public Integer call() throws Exception{ System.out.println("进来了"); return 1024; } } public class CallableDemo{ public static void main(String[] args){ FuterTask<Integer> futerTask = new FuterTask<>(new MyThread); Thread t1 = new Thread(futerTask,"AAA"); t1.start(); int result01 = 100; int result02 = futerTask.get(); System.out.println(result01+result02); } }
结果:1124
8.2 线程池的优势
Executor顶级接口和工具包Executors
底层:阻塞队列
1.降低资源消耗
2.提高响应速度
3.提高线程的可管理性
// 拓展工具类
// Array Arrays
// Collection Collections
// Executor Executors
8.3 线程池实现的方式【3种核心】
工作中你用那个??? 哪个都不用的
阿里巴巴开发手册:不允许使用Executors区创建,而是使用ThreadPoolExecutor的方式,这样的处理方式更加明确线程池的运行规则,避免资源耗尽。
但是也要学习!!!!!!如下:
第一种【重要】:
public class MyThreadPoolDemo{ public static void main(String[] args){ // 1个线程池 5个线程 ExecutorService threadPool = Executors.newFixedThreadPool(5); try{ for(int i = 1;i<=10;i++){//10个用户 threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+"办理业务"); }); } }catch(...){ }finally{ thread.shutdown(); } } }
第二种:
public class MyThreadPoolDemo{ public static void main(String[] args){ // 1个线程池 1个线程 ExecutorService threadPool = Executors.newSingleThreadExecutor(); try{ for(int i = 1;i<=10;i++){//10个用户 threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+"办理业务"); }); } }catch(...){ }finally{ thread.shutdown(); } } }
第三种:
public class MyThreadPoolDemo{ public static void main(String[] args){ // 1个线程池 不定线程 ExecutorService threadPool = Executors.newCacgedThreadPool(); try{ for(int i = 1;i<=10;i++){//10个用户 threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+"办理业务"); }); } }catch(...){ }finally{ thread.shutdown(); } } }
8.4 线程池7大参数
8.5 线程池拒绝策略
8.6 手写线程池【大厂工作核心–7大参数】
public class MyThreadPoolDemo{ public static void main(String[] args){ ExecutorService threadPool = new ThreadPoolExecutor( 2,//核心数 5,//最大线程数 1L,//活跃时间 TimeUint.SECONDS,//单位 new LinkedBlockingQueue<Runnable>(3),//阻塞队列大小个数 Executors.defaultThreadFactory(),//线程工厂 new ThreadPoolExecutor.AbortPolicy());//拒绝策略,会抛异常 try{ for(int i = 1;i<=5;i++){ threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+"办理业务"); }); } }catch(...){ }finally{ threadPool.shutdown(); } } }
8.7 如何合理配置线程的数量呢?
回答:
1.CPU密集型?
2.IO密集型?
1.获取CPU密集型
Runtime.getRuntime().getProcessors()
一般为:CPU核数+1个线程
2.IO密集型
io密集型的任务并不是一直在执行任务,应该配置尽可能多的线程
一般为:CPU核数*2