Juc全网最全学习笔记【遇见狂神说】,华为面试题及答案java

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

并发(多线程操作同一个资源)

  • CPU 一核 ,模拟出来多条线程,天下武功,唯快不破,快速交替并行(多个人一起行走)

并行:多个人一起走

  • CPU多核,多个线程可以同时执行,线程池

public class Test1{

    public static void main(String[] args){

        //获取CPU的核数

        //CPU密集型,IO密集型

        System.out.println(Runtime.getRuntime().availableProcessors());

    }

}



并发编程的本质:充分利用CPU的资源

线程有几个状态


public enum State {



   	//运行

       NEW,



   	//运行

       RUNNABLE,



   	//阻塞

       BLOCKED,



   	//等待

       WAITING,



   	//超时等待

       TIMED_WAITING,



   	//终止

       TERMINATED;

   }





wait/sleep 区别

1、 来自不同的类

wait => Object

sleep => Thread

一般企业中使用的休眠是:


TimeUnit.DAYS.sleep(1);//休眠一天

TimeUnit.SECONDS.sleep(1);//休眠1s



2、 关于锁的释放

wait 会释放锁

sleep 睡觉了,不会释放!

3、 使用的范围是不同的

wait必须使用在代码块中

.

sleep 可以再任何地方睡

4、是否需要捕获异常

wait 不需要捕获异常

sleep 必须要捕获异常

3、Lock锁(重点)

传统 Synchronized


/**

* 真正的多线程开发

* 线程就是一个单独的资源类,没有任何的附属操作!

*/

public class SaleTicketDemo01 {

   public static void main(String[] args) {

       //多线程操作

       //并发:多线程操作同一个资源类,把资源类丢入线程

       Ticket ticket = new Ticket();



       //@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式

       new Thread(()->{

           for(int i=0;i<40;i++){

               ticket.sale();

           }

       },"A").start();

       new Thread(()->{

           for(int i=0;i<40;i++){

               ticket.sale();

           }

       },"B").start();

       new Thread(()->{

           for(int i=0;i<40;i++){

               ticket.sale();

           }

       },"C").start();

   }

}

//资源类

//属性+方法

//oop

class Ticket{

   private int number=50;



   //卖票的方式

   // synchronized 本质:队列,锁

   public synchronized void sale(){

       if(number>0){

           System.out.println(Thread.currentThread().getName()+" 卖出了第"+number+" 张票,剩余:"+number+" 张票");

           number--;

       }

   }

}





Lock 接口

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

公平锁:十分公平:可以先来后到

非公平锁:十分不公平:可以插队 (默认为非公平锁

Synchronized 和 Lock 区别

  • ​ Synchronized 内置的Java关键字, Lock 是一个Java类

  • ​ Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁

  • ​ Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁

  • ​ Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去;

  • ​ Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以自己设置);

  • ​ Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!

锁是什么,如何判断锁的是谁!

4、生产者和消费者问题

面试的:单例模式、排序算法、生产者和消费者、死锁

生产者和消费者问题 Synchronized 版


public class A {

    public static void main(String[] args) {

        Data data = new Data();



        new Thread(()->{for(int i=0;i<10;i++) {

            try {

                data.increment();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

        },"A").start();

        new Thread(()->{for(int i=0;i<10;i++) {

            try {

                data.decrement();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }},"B").start();

    }

}

class Data{

    //数字  资源类

    private int number = 0;



    //+1

    public synchronized void increment() throws InterruptedException {

        if(number!=0){

            //等待操作

            this.wait();

        }

        number++;

        System.out.println(Thread.currentThread().getName()+"=>"+number);

        //通知其他线程 我+1完毕了

        this.notifyAll();

    }



    //-1

    public synchronized void decrement() throws InterruptedException {

        if(number==0){

            //等待操作

            this.wait();

        }

        number--;

        System.out.println(Thread.currentThread().getName()+"=>"+number);

        //通知其他线程  我-1完毕了

        this.notifyAll();

    }



}





问题存在,A B C D 4 个线程! 虚假唤醒

在这里插入图片描述

**解决方案:**if 改为 while 判断


/**

* 判断等待,业务,通知

*/

class Data2{//资源类  数字

   private int number = 0;



   Lock lock = new ReentrantLock();

   Condition condition = lock.newCondition();



   //condition.await();//等待

   //condition.signalAll();//唤醒全部



   //+1

   public void increment() throws InterruptedException {

       try {

           lock.lock();

           //业务代码

           while (number !=0){

               //等待操作

               condition.await();

           }

           number++;

           System.out.println(Thread.currentThread().getName()+"=>"+number);

           //通知其他线程,我+1完毕了

           condition.signalAll();

       }catch (Exception e){

           e.printStackTrace();

       }finally {

           lock.unlock();

       }



   }

   //-1

   public void decrement() throws InterruptedException {

       try {

           lock.lock();

           //业务代码

           while (number == 0){

               //等待操作

               condition.await();

           }

           number --;

           System.out.println(Thread.currentThread().getName()+"=>"+number);

           //通知其他线程,我-1完毕了

           condition.signalAll();

       }catch (Exception e){

           e.printStackTrace();

       }finally {

           lock.unlock();

       }



   }

}



JUC版的生产者和消费者问题

通过Lock 找到 Condition

代码实现:


/**

 * 判断等待,业务,通知

 */

class Data2{//资源类  数字

    private int number = 0;



    Lock lock = new ReentrantLock();

    Condition condition = lock.newCondition();



    //condition.await();//等待

    //condition.signalAll();//唤醒全部



    //+1

    public void increment() throws InterruptedException {

        try {

            lock.lock();

            //业务代码

            while (number !=0){

                //等待操作

                condition.await();

            }

            number++;

            System.out.println(Thread.currentThread().getName()+"=>"+number);

            //通知其他线程,我+1完毕了

            condition.signalAll();

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            lock.unlock();

        }



    }

    //-1

    public void decrement() throws InterruptedException {

        try {

            lock.lock();

            //业务代码

            while (number == 0){

                //等待操作

                condition.await();

            }

            number --;

            System.out.println(Thread.currentThread().getName()+"=>"+number);

            //通知其他线程,我-1完毕了

            condition.signalAll();

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            lock.unlock();

        }



    }

}



5、8锁现象

如何判断锁的是谁!

锁会锁住:对象、Class

深刻理解我们的锁:

问题一:标准情况下,两个线程先打印 发短信 还是 打电话

在这里插入图片描述

结果是:

在这里插入图片描述

那么问题来了,为什么是这种顺序来打印的,是按顺序执行的吗?答案显然是错误的!

问题二:我们让打短信延迟4s

在这里插入图片描述

现在结果是什么情况呢?

结果依然是:发短信 打电话!

原因: synchronized 锁的对象是方法的调用者!两个方法使用的是同一把锁,谁先拿到,谁先执行!

问题三:添加一个普通方法,结果先执行哪一个呢?

在这里插入图片描述

结果:先执行hello()在打印发短信!原因是hello()是一个普通方法,并不是同步方法,不受Synchronized锁的影响,如果把发短信里的TimeUnit.SECONDS.sleep(4)去掉,那么就会顺序执行,限制性发短信再执行hello()。原因方法sendSms()hello()两者并不会产生影响,在sendSms()中加入延时时,在线程开始时,就会等待4s再执行,去掉之后,两个方法并不会有谁等待谁的关系,就会按照顺序进行执行!(个人理解)

问题四:如果使用两个对象,分别调用发短信 和 打电话 那么顺序是什么呢?

在这里插入图片描述

结果: 打电话 发短信。

原因: 在发短信中 延时了4s,再加上Synchronized锁的对象是方法的调用者,如果有两把锁,就会根据执行时间来决定打印顺序!

问题 5、6 如果在方法上加上static变成静态方法!结果又该如何?

在这里插入图片描述

结果: 发短信 打电话

原因: 对于static静态方法来说,对于整个类Class来说只有一份,对于不同的对象使用的是同一份方法,相当于这个方法是属于这个类的,如果静态方法static使用了Synchronized锁定,那么这个Synchronized锁会锁住整个对象!不管多少个对象,对于静态的锁都只有一把锁,谁先拿到这个锁谁先执行!其他进程都需要等待!

问题七:如果把两个方法设置为一个静态方法、一个同步方法,结果又将如何?

在这里插入图片描述

结果: 打电话 发短信

原因: 因为一个锁的是Class类模板,一个锁的是对象的调用者,call()不需要等待发短信,直接运行!

问题八:一个静态方法、一个同步方法,使用两个对象进行分别调用,顺序是什么呢?

在这里插入图片描述

结果: 打电话 发短信

原因: 因为两个对象,一样的原因,两把锁锁的不是同一个东西,所以后面的第二个对象不需要等待第一个对象去执行!

6、集合类不安全

List不安全


//java.util.ConcurrentModificationException 并发修改异常

public class ListTest{

    public static void main(String[] args){

        List<String> list = new ArrayList<>();

        for(int i = 1;i<=30;++i){

            new Thread(()->{

                list.add(UUID.randomUUID().toString().substring(0,5));

            },String.valueOf(i)).start();

        }

    }

}



执行结果:

在这里插入图片描述

结果:ArrayList在并发情况下是不安全的!

解决方案:

  • 切换成Vector就是线程安全的!

public class ListTest{

    public static void main(String[] args){

        List<String> list = new Vector<>();

        for(int i = 1;i<=30;++i){

            new Thread(()->{

                list.add(UUID.randomUUID().toString().substring(0,5));

            },String.valueOf(i)).start();

        }

    }

}



在这里插入图片描述

  • 使用Collections.synchronizedList(new ArrayList<>());

public class ListTest{

    public static void main(String[] args){

        List<String> list = Collections.synchronizedList(new ArrayList<>());

        for(int i = 1;i<=30;++i){

            new Thread(()->{

                list.add(UUID.randomUUID().toString().substring(0,5));

            },String.valueOf(i)).start();

        }

    }

}



  • 使用JUC中的包:List<String> list = new CopyOnWriteArrayList<>();

public class ListTest{

    public static void main(String[] args){

        List<String> list = new CopyOnWriteArrayList<>();

        for(int i = 1;i<=30;++i){

            new Thread(()->{

                list.add(UUID.randomUUID().toString().substring(0,5));

            },String.valueOf(i)).start();

        }

    }

}



CopyOnWriteArrayList:写入时复制!COW计算机程序设计领域的一种优化策略

多个线程调用的时候,list,读取的时候,固定的,写入(覆盖);在写入的时候避免覆盖,造成数据的问题!

CopyOnWriteArrayList 比 Vector 厉害在哪里?

  • VectoraddElement()方法使用的是Synchronized,一般使用Synchronized效率较低

在这里插入图片描述

  • CopyOnWriteArrayListadd方法使用的是lock

    在这里插入图片描述

Set不安全

在这里插入图片描述

List属于同级,由于List在并发情况下不安全,则Set也是不安全的

解决方案:

  • 使用Collections工具类的synchronized包装的Set

  • 使用CopyOnWriteArraySet写入复制的JUC解决方案


//java.util.ConcurrentModificationException

public class SetTest {

    public static void main(String[] args) {



        Set<String> set1 = new HashSet<>();

        //Set<String> set = Collections.synchronizedSet(new HashSet<>());

        Set<String> set = new CopyOnWriteArraySet<>();

        for (int i = 1; i <= 100; i++) {

            new Thread(()->{

                set.add(UUID.randomUUID().toString().substring(0,5));

                System.out.println(set);

            },String.valueOf(i)).start();

        }

    }

}



HashSet底层是什么?

在这里插入图片描述

通过底层来看,HashSet的底层其实就是一个HashMap


public HashSet() {

   map = new HashMap<>();

}



//add 本质其实就是一个map的key,map的key是无法重复的,所以使用的就是map存储

//hashSet就是使用了hashmap key不能重复的原理

public boolean add(E e) {

        return map.put(e, PRESENT)==null;

}

//PRESENT是什么? 是一个常量  不会改变的常量  无用的占位

private static final Object PRESENT = new Object();





Map不安全


//map是这样用的吗? 不是,工作中不使用HashMap

//默认等价于什么? new HashMap<>(16,0.75);

//Map<String, String> map = new HashMap<>();



HashMap默认加载因子是0.75,默认的初始容量是16

在这里插入图片描述

同样的HashMap基础类也存在并发修改异常


public class HashMapTest {



    public static void main(String[] args) {

        //map是这样用的吗? 不是,工作中不使用HashMap

        //默认等价于什么? new HashMap<>(16,0.75);

        //Map<String, String> map = new HashMap<>();



        // Collections.synchronizedMap()

        Map<String, String> map = new ConcurrentHashMap<>();



        for (int i = 1; i <= 30; i++) {

            new Thread(()->{

                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));

                System.out.println(map);

            },String.valueOf(i)).start();

        }

    }

}



解决方案:

  • 使用Collections.synchronizedMap(new HashMap<>());处理

  • 使用new ConcurrentHashMap<>()进行并发处理

7、Callable(简单)

在这里插入图片描述

  • 可以有返回值

  • 可以抛出异常

  • 方法不同 run()/call()

代码测试


public class CallableTest{

    public static void main(String[] args){

        for(int i = 1;i<10;++i){

            new Thread(new MyThread()).start;

        }

    }

}

class MyThread implements Runnable{

    @Override

    public void run(){

        System.out.println(Thread.currentThread().getName());

    }

}



使用Callable进行多线程操作:

在这里插入图片描述

Callable泛型T就是Call运行方法的返回值类型

Callable如何放入到Thread里面呢?

对于Thread运行,只能传入Runnable类型的参数

在这里插入图片描述

FutureTask中可以接受Callable参数

在这里插入图片描述

这样我们就可以先把Callable放入FutureTask中,如何再把FutureTask放入到Thread就可以了!


public class CallableTest {

    public static void main(String[] args)throws Exception {

        //new Thread(new Runnable()).start();

        //new Thread(new FutuerTask<V>()).start

        //构造器

        //new Thread(new FutuerTask<V>( Callable )).start



        for (int i = 1; i <= 10; i++) {

            MyThread thread = new MyThread();

            //适配类:FutureTask

            FutureTask<String> futureTask = new FutureTask<>(thread);

            //放入Thread使用

            new Thread(futureTask,String.valueOf(i)).start();

            //获取返回值

            String s = futureTask.get();

            System.out.println("返回值"+s);

        }

    }

}



class MyThread implements Callable<String>{



    @Override

    public String call() throws Exception {

        System.out.println("Call:"+Thread.currentThread().getName());

        return "String"+Thread.currentThread().getName();

    }

}



这样我们就可以使用Callable来进行多线程编程了。并且我们发现可以有返回值 了,并且可以抛出异常

在这里插入图片描述

8、常用的辅助类(必须会!)

8.1 CountDownLatch

在这里插入图片描述

其实就是一个减法计数器,对于计数器归零之后在进行后面的操作,这是一个计数器


//计数器

public class CountDownLatchDemo {

    public static void main(String[] args) {



        //总数是6 必须要执行的任何的时候,再使用!

        CountDownLatch countDownLatch = new CountDownLatch(6);



        for (int i = 1; i <= 6; i++) {

            new Thread(()->{

                System.out.println(Thread.currentThread().getName()+"走了");

                countDownLatch.countDown();// 数量-1

            },String.valueOf(i)).start();

        }



        try {

            countDownLatch.await();//等待计数器归 0  ,然后再向下执行

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println("关门");

    }

}



主要方法:

  • countDown减一操作

  • await等待计数器归零

await等待计数器为0,就唤醒,再继续向下执行。

8.2 CyclickBarrier

在这里插入图片描述

其实就是一个加法计数器


public class CyclicBarrierDemo {

    public static void main(String[] args) {

        /*

        *集齐七颗龙珠召唤神龙

        * */

        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{

            System.out.println("召唤神龙成功!");

        });



        for (int i = 1; i <= 7 ; i++) {

            final int temp = i;

            new Thread(()->{

                System.out.println(Thread.currentThread().getName()+"收集了"+temp+"颗龙珠");

                try {

                    cyclicBarrier.await();//等待

                } catch(Exception e){

                    e.printStackTrace();

                }

            }).start();



        }



    }

}



8.3 Semaphore

Semaphore:信号量

代码模拟抢车位


public class SemaphoreDemo {

    public static void main(String[] args) {

        /**

         * 参数:线程数量   应用场景:限流!

         */

        Semaphore semaphore = new Semaphore(3);



        for (int i = 1; i <= 3; i++) {

            new Thread(()->{

                //acquire() 得到

                try {

                    semaphore.acquire();//抢到车位

                    System.out.println(Thread.currentThread().getName()+"抢到了车位");

                    TimeUnit.SECONDS.sleep(2);

                    System.out.println(Thread.currentThread().getName()+"离开了车位");

                } catch (InterruptedException e) {

                    e.printStackTrace();

                } finally {

                    //release() 释放

                    semaphore.release();//释放

                }

            },String.valueOf(i)).start();

        }

    }

}



原理:

semaphore.acquire()获取资源,如果资源已经使用完了,就等待资源释放后再进行使用!

semaphore.release()释放,会将当前的信号量释放+1,然后唤醒等待的线程!

应用场景:

  • 多个共享资源互斥的使用

  • 并发限流,控制最大的线程数

9、阻塞队列

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

BlockingQueue

在这里插入图片描述

什么情况下会使用阻塞队列?

  • 多线程并发处理 线程A调用线程B,则A必须等待线程B执行完之后才能执行

  • 线程池

学会使用队列

| 方式 | 抛出异常 | 不会抛出异常,有返回值 | 阻塞 等待 | 超时等待 |

| — | — | — | — | — |

| 添加 | add() | offer() | put() | offer(,) |

| 移除 | remove() | poll() | take() | poll(,) |

| 检测队首元素 | element() | peek() | - | - |


/**

* 抛出异常

*/

public static void test1(){

   //参数:队列的大小

   ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

   // java.lang.IllegalStateException: Queue full 队列满

   System.out.println(blockingQueue.add("a"));

   System.out.println(blockingQueue.add("b"));

   System.out.println(blockingQueue.add("c"));



   System.out.println("========================");

   // java.util.NoSuchElementException

   System.out.println(blockingQueue.remove());

   System.out.println(blockingQueue.remove());

   System.out.println(blockingQueue.remove());

}




/**

 * 不抛出异常

 */

public static void test2(){

    //队列的大小

    ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

    //

    System.out.println(blockingQueue.offer("a"));

    System.out.println(blockingQueue.offer("b"));

    System.out.println(blockingQueue.offer("c"));

    //System.out.println(blockingQueue.offer("d"));//false 不抛出异常!



    System.out.println("-=======================");



    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll());//null 不抛出异常!

}




/*

 * 等待,阻塞(一直阻塞)

 * */

public static void test3() throws InterruptedException {

    ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);



    blockingQueue.put("a");

    blockingQueue.put("b");

    blockingQueue.put("c");

    //blockingQueue.put("d");//队列没有位置了,一直阻塞



    System.out.println(blockingQueue.take());

    System.out.println(blockingQueue.take());

    System.out.println(blockingQueue.take());

    //System.out.println(blockingQueue.take()); 没有这个元素,一直等待

}




/*

 * 等待,阻塞(等待超时)

 * */

public static void test4() throws InterruptedException {

    ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(blockingQueue.offer("a"));

    System.out.println(blockingQueue.offer("b"));

    System.out.println(blockingQueue.offer("c"));

    //System.out.println(blockingQueue.offer("d", 3, TimeUnit.SECONDS));//超时2秒

    System.out.println("==========================");

    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll());

    System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));

}



SynchronousQueue 同步队列


/**

 * 同步队列

 * 和其他的BlockingQueue 不一样,SynchronousQueue 不存储元素

 * put了一个元素,必须从里面先take取出来,否则不能在put进去值!

 */

public class SynchronousQueueTest {

    public static void main(String[] args) {

        SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();//同步队列



        new Thread(()->{

            try {

                System.out.println(Thread.currentThread().getName()+" put 1");

                synchronousQueue.put("1");

                System.out.println(Thread.currentThread().getName()+" put 2");

                synchronousQueue.put("2");

                System.out.println(Thread.currentThread().getName()+" put 3");

                synchronousQueue.put("3");

            } catch (Exception e) {

                e.printStackTrace();

            }

        },"T1").start();

        new Thread(()->{

            try {

                TimeUnit.SECONDS.sleep(3);

                System.out.println(Thread.currentThread().getName()+ synchronousQueue.take());

                TimeUnit.SECONDS.sleep(3);

                System.out.println(Thread.currentThread().getName()+synchronousQueue.take());

                TimeUnit.SECONDS.sleep(3);

                System.out.println(Thread.currentThread().getName()+synchronousQueue.take());

            } catch (Exception e) {

                e.printStackTrace();

            }

        },"T2").start();



    }

}



10、线程池(重点)

池化技术

程序的运行,本质:占用系统的资源!优化资源的使用!=> 池化技术

线程池、连接池、对象池、内存池///… 创建、销毁十分浪费资源

池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。

线程池的好处:

  • 降低资源的消耗

  • 提高响应的速度

  • 方便管理

线程复用,可以控制最大并发数,管理线程

线程池:三大方法

在这里插入图片描述


/**

 * @function Executors 工具类、3大方法

 * @author 派 大 星

 * @date 2022/3/31 22:49

 */

public class Demo01 {

    public static void main(String[] args) {

        // 单个线程

        // ExecutorService threadPool = Executors.newSingleThreadExecutor();



        // 创建一个固定的线程池的大小

        // ExecutorService threadPool = Executors.newFixedThreadPool(5);



        // 可伸缩的,遇强则强,遇弱则弱

        ExecutorService threadPool = Executors.newCachedThreadPool();



        try {

            for (int i = 1; i <= 100; i++) {

                threadPool.execute(()->{

                    System.out.println(Thread.currentThread().getName()+" ok");

                });

            }

        }catch (Exception e){

            e.printStackTrace();

        }finally {

            // 线程池用完,程序执行完关闭线程池

            threadPool.shutdown();

        }

    }

}



7大参数

源码分析:


public static ExecutorService newSingleThreadExecutor() {

    return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,

                                                                          new LinkedBlockingQueue<Runnable>()));

}



public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

}



public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE ,// 约21亿 oom溢出

                                  60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());

}



// 本质:ThreadPoolExecutor()

    

public ThreadPoolExecutor(int corePoolSize,//核心线程池大小

                              int maximumPoolSize,// 最大核心线程池大小

                              long keepAliveTime,// 超时了没人调用就会释放

                              TimeUnit unit,// 超时单位

                              BlockingQueue<Runnable> workQueue,// 阻塞队列

                              ThreadFactory threadFactory,// 线程工厂,创建线程的,一般不用动

                              RejectedExecutionHandler handler// 拒绝策略) {

    if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)

        throw new IllegalArgumentException();

    if (workQueue == null || threadFactory == null || handler == null)

        throw new NullPointerException();

    this.corePoolSize = corePoolSize;

    this.maximumPoolSize = maximumPoolSize;

    this.workQueue = workQueue;

    this.keepAliveTime = unit.toNanos(keepAliveTime);

    this.threadFactory = threadFactory;

    this.handler = handler;

}



在这里插入图片描述

手动创建一个线程池


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 7:12

 * 四种拒绝策略

 */

public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(

                2,

                5,

                3,

                TimeUnit.SECONDS,

                new LinkedBlockingDeque<>(3),

                Executors.defaultThreadFactory(),

                new ThreadPoolExecutor.DiscardOldestPolicy());



        try {

            for (int i = 1; i <= 9; i++) {

                //使用自定义线程池创建线程

                //最大承载:Deque + max(双端队列 + 最大线程池数)

                threadPoolExecutor.execute(()->{

                    System.out.println(Thread.currentThread().getName()+" ok");

                });

            }

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            //关闭线程

            threadPoolExecutor.shutdown();

        }

    }

}



四种拒绝策略

在这里插入图片描述


/**

 * new ThreadPoolExecutor.AbortPolicy() 银行满了,还有人进来,不处理这个人,抛出异常

 * new ThreadPoolExecutor.CallerRunsPolicy() 哪来的去哪里!

 * new ThreadPoolExecutor.DiscardPolicy() 队列满了,丢掉任务,不会抛出异常!

 * new ThreadPoolExecutor.DiscardOldestPolicy() 队列满了。尝试去和最早的竞争(竞争成功,执行,竞争不成功,则丢掉任务),也不会抛出异常!

 */



小结和拓展

了解:IO密集型、CPU密集型


// 最大线程到底如何定义?

// 1. CPU 密集型 CPU几核,就是几,可以保持CPU的效率最高!Runtime.getRuntime().availableProcessors()

// 2. IO 密集型 > 判断你程序中十分消耗资IO的线程

// 程序 15个大型任务,io十分占用资源



11、四大函数式接口(必须掌握)

新时代程序员:lambda表达式、链式编程、函数式接口、Stream流式计算

函数式接口:只有一个方法的接口


@FunctionalInterface

public interface Runnable {

    public abstract void run();

}

//简化编程模型,在新版本框架底层大量应用

//foreach(消费者类型的函数式接口)



Function函数式接口

在这里插入图片描述


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 8:05

 * Function 函数型接口,有一个输入参数,有一个输出

 * 只要是函数型接口,可以用lambda表达式简化

 *

 */

public class Demo01 {

    public static void main(String[] args) {

        // 工具类:输出输入的值

        //

//        Function<String, String> function = new Function<String, String>() {

//            @Override

//            public String apply(String s) {

//                return s;

//            }

//        };

        // lambda表达式简化

        Function<String, String> function = (str)->{return str;};



        System.out.println(function.apply("123"));

    }

}



Predicate断定型接口:有一个输入参数,返回值只能是 布尔值!


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 19:42

 * 断定性接口:有一个输入参数,返回值只能是 布尔值!

 */

public class Demo02 {

    public static void main(String[] args) {

        //判断字符串是否为空

//        Predicate<String> predicate = new Predicate<String>() {

//            @Override

//            public boolean test(String s) {

//                return s.isEmpty();

//            }

//        };



        Predicate<String> predicate = (str)->{

            return str.isEmpty();

        };

        System.out.println(predicate.test(""));

    }

}



Consumer消费型接口

在这里插入图片描述


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 19:48

 * Consumer 消费型接口:只有输入,没有返回值!

 */

public class Demo03 {

    public static void main(String[] args) {

//        Consumer<String> consumer = new Consumer<String>() {

//            @Override

//            public void accept(String s) {

//                System.out.println(s);

//            }

//        };



        Consumer<String> consumer =(str)->{

            System.out.println(str);

        };



        consumer.accept("dadada");

    }

}



Supplier供给型接口

在这里插入图片描述


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 19:52

 * Supplier 消费型接口:没有参数,只有返回值!

 */

public class Demo04 {

    public static void main(String[] args) {

//        Supplier<String> supplier = new Supplier<String>() {

//            @Override

//            public String get() {

//                return "null";

//            }

//        };

        Supplier<String> supplier =()->{return "xxxx";};

        System.out.println(supplier.get());

    }

}



12、Stream流式计算

什么是Stream流式计算?

大数据:存储+计算

集合、Mysql 本质就是存储东西!

在这里插入图片描述


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 20:14

 * 题目要求:一分钟内完成此题,只能用一行代码实现!

 * 现有5个用户!筛选

 * 1. ID必须是偶数

 * 2. 年龄必须大于23

 * 3. 用户名转为大写字母

 * 4. 用户名字母倒着排序

 * 5. 只输出一个用户

 */

public class Test {

    public static void main(String[] args) {

        User user1 = new User(1,"a",21);

        User user2 = new User(2,"b",22);

        User user3 = new User(3,"c",23);

        User user4 = new User(4,"d",24);

        User user5 = new User(6,"e",25);

        List<User> users = Arrays.asList(user1, user2, user3, user4, user5);

        //集合就是存储

        users.stream()

                // 过滤 filter(Predicate<? super T> predicate);

                .filter(u->{return u.getId()%2==0;})

                .filter(u->{return u.getAge()>23;})

                // map(Function<? super T, ? extends R> mapper);

                .map(u->{return u.getName().toUpperCase();})

                //sorted(Comparator<? super T> comparator);

                .sorted((u1,u2)->{return u2.compareTo(u1);})

                .limit(1)

                .forEach(System.out::println);

    }

}



13、ForkJoin

什么是ForkJoin

ForkJoin在JDK1.7 ,并行执行任务!提高效率,大数据量!

在这里插入图片描述

ForkJoin特点:工作窃取

这个里面维护的都是双端队列

在这里插入图片描述

如何理解工作窃取:现有两个线程A、B,假设B提前执行结束,但是B不能一直等待A执行结束,所以B会窃取A的任务进行执行

ForkJoin如何使用

在这里插入图片描述

在这里插入图片描述


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 21:04

 * 求和计算任务

 * 如何使用ForkJoin

 * 1. ForkJoinPool 通过它来执行

 * 2. 计算任务 ForkJoinPool.execute(ForkJoinTask task)

 * 3. 计算类必须继承 ForkJOinTask

 */

public class ForkJoinDemo extends RecursiveTask<Long> {



    private Long start;

    private Long end;

    //临界值

    private Long temp = 10000L;



    public ForkJoinDemo(Long start, Long end) {

        this.start = start;

        this.end = end;

    }



   public void test(){



   }



   //计算方法

    @Override

    protected Long compute() {

        if (end-start < temp){

            Long sum = 0L;

            for (Long i = start; i <= end; i++) {

                sum+=i;

            }

            return sum;

        }else {//使用ForkJoin

            //中间值

            long middle = (start + end) / 2;

            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);

            //拆分任务,把任务压入线程队列

            task1.fork();

            ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);

            //拆分任务,把任务压入线程队列

            task2.fork();

            return task1.join() + task2.join();

        }

    }

}



测试:


/**

 * @author 派 大 星

 * @function

 * @date 2022/4/1 21:35

 */

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        test3();

    }



    public static void test1(){

        //3724

        Long sum = 0L;

        long start = System.currentTimeMillis();

        for (int i = 1; i <= 10_0000_0000; i++) {

            sum+=i;

        }

        long end = System.currentTimeMillis();

        System.out.println("sum="+sum+"时间:"+(end-start));



# 惊喜

最后还准备了一套上面资料对应的面试题(有答案哦)和面试时的高频面试算法题(如果面试准备时间不够,那么集中把这些算法题做完即可,命中率高达85%+)

![image.png](https://img-blog.csdnimg.cn/img_convert/f0cd12f0f183937b0caf59073b72a94d.webp?x-oss-process=image/format,png)


![image.png](https://img-blog.csdnimg.cn/img_convert/a09394b5b2a8680c4eea484291bf2d7c.webp?x-oss-process=image/format,png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)**
![img](https://img-blog.csdnimg.cn/img_convert/74a9f8d24668d6dbbf08a45d58d1ae8c.jpeg)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rS-IOWkpyDmmJ8u,size_12,color_FFFFFF,t_70,g_se,x_16)



如何理解`工作窃取`:现有两个线程A、B,假设B提前执行结束,但是B不能一直等待A执行结束,所以B会`窃取`A的任务进行执行



> ForkJoin如何使用



![在这里插入图片描述](https://img-blog.csdnimg.cn/b8425b8145dc448b9e1a61e6c9d117b9.png)  

![在这里插入图片描述](https://img-blog.csdnimg.cn/5fbf306b114a495b9560d3911463d830.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rS-IOWkpyDmmJ8u,size_18,color_FFFFFF,t_70,g_se,x_16)



/**

  • @author 派 大 星

  • @function

  • @date 2022/4/1 21:04

  • 求和计算任务

  • 如何使用ForkJoin

    1. ForkJoinPool 通过它来执行
    1. 计算任务 ForkJoinPool.execute(ForkJoinTask task)
    1. 计算类必须继承 ForkJOinTask

*/

public class ForkJoinDemo extends RecursiveTask {

private Long start;

private Long end;

//临界值

private Long temp = 10000L;



public ForkJoinDemo(Long start, Long end) {

    this.start = start;

    this.end = end;

}

public void test(){

}

//计算方法

@Override

protected Long compute() {

    if (end-start < temp){

        Long sum = 0L;

        for (Long i = start; i <= end; i++) {

            sum+=i;

        }

        return sum;

    }else {//使用ForkJoin

        //中间值

        long middle = (start + end) / 2;

        ForkJoinDemo task1 = new ForkJoinDemo(start, middle);

        //拆分任务,把任务压入线程队列

        task1.fork();

        ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);

        //拆分任务,把任务压入线程队列

        task2.fork();

        return task1.join() + task2.join();

    }

}

}




**测试:**



/**

  • @author 派 大 星

  • @function

  • @date 2022/4/1 21:35

*/

public class Test {

public static void main(String[] args) throws ExecutionException, InterruptedException {

    test3();

}



public static void test1(){

    //3724

    Long sum = 0L;

    long start = System.currentTimeMillis();

    for (int i = 1; i <= 10_0000_0000; i++) {

        sum+=i;

    }

    long end = System.currentTimeMillis();

    System.out.println("sum="+sum+"时间:"+(end-start));

惊喜

最后还准备了一套上面资料对应的面试题(有答案哦)和面试时的高频面试算法题(如果面试准备时间不够,那么集中把这些算法题做完即可,命中率高达85%+)

[外链图片转存中…(img-LBO43jJP-1713421854249)]

[外链图片转存中…(img-ECjAXqAE-1713421854249)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-ZaQEA1cS-1713421854249)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值