2020大厂面试JUC线程重要技术点【集合+线程+阻塞队列+线程池】(下)

简介: 2020大厂面试JUC线程重要技术点【集合+线程+阻塞队列+线程池】(下)

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();
  }
}

20200721172246175.png

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();
  }
}

20200722093755975.png


八、线程池


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

20200722143801641.png



底层:阻塞队列


1.降低资源消耗

2.提高响应速度

3.提高线程的可管理性

// 拓展工具类
// Array Arrays
// Collection Collections
// Executor Executors


8.3 线程池实现的方式【3种核心】


20200722144322929.png

工作中你用那个??? 哪个都不用的

阿里巴巴开发手册:不允许使用Executors区创建,而是使用ThreadPoolExecutor的方式,这样的处理方式更加明确线程池的运行规则,避免资源耗尽。


20200722164118815.png


但是也要学习!!!!!!如下:


第一种【重要】:


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();
    }
  }
}

20200722145120484.png


第二种:


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();
    }
  }
}

20200722145316943.png


第三种:


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();
    }
  }
}

20200722145507650.png


8.4 线程池7大参数

20200722150810617.png

20200722151729871.png

20200722151639341.png

8.5 线程池拒绝策略

20200722160435542.png

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

目录
相关文章
|
23天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
100 38
|
21天前
|
Java
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
46 2
|
23天前
|
Prometheus 监控 Cloud Native
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
60 4
|
23天前
|
Prometheus 监控 Cloud Native
在 Java 中,如何使用线程池监控以及动态调整线程池?
【10月更文挑战第22天】线程池的监控和动态调整是一项重要的任务,需要我们结合具体的应用场景和需求,选择合适的方法和策略,以确保线程池始终处于最优状态,提高系统的性能和稳定性。
94 2
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
25天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
25天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
16 2
|
25天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
25天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
25天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
34 1