jvm和juc

目录

JVM

1.jvm内存结构

2.jvm每块作用是什么

4.jvm常用参数(jvm调优)

5.垃圾回收--算法

6.垃圾回收--工具(垃圾回收器)

JUC

sleep和wait的区别

串行,并发,并行的区别

synchronized关键字

锁膨胀过程(jdk对synchronize关键字的优化)

锁消除,锁粗化,自旋锁,自适应自旋锁(synchronize知识)

Lock接口

lock接口的方法

Lock锁的可重入锁、公平锁

读写锁->读锁释放之后写锁才能被抢

定制化通信

中断锁

lock和synchronized作比较

程序计数器

循环栅栏

信号灯

创建多线程的实现方式

1.继承Thread类

2.实现Runnable接口

3.线程池

4.Callable+FutureTask

5.CompletableFuture->组合式异步编程(异步编排)

6.Fork Join

7.并行计算

8.Timer定时任务

9.Spring的一部方法调用

线程池解析


JVM

1.jvm内存结构

方法区(共享)

1.存储构造方法,常量池,静态变量,接口定义.

栈(独立)

1.存储方法的返回值,方法的参数,方法的变量(局部变量),入栈和出栈的操作,
  栈帧(方法的操作进度),
2.栈随着线程的创建而创建,随着线程的消失而消失,每个线程拥有自己的栈.

本地方法栈

1.用于调用系统级别的一些方法

堆(共享)

新生代:所有的对象都"可以"是新生代(每个线程都可能会new一些新对象,而且这些对象可能
      用一下就不用了)
    区域划分:伊甸园区域,幸存者区域(From区域 To区域)
       内存占比  8       :         1  :    1
    大部分创建(new)出来的对象都会放在伊甸园区域,如果伊甸园区域满了会触发垃圾回收.
    垃圾回收流程:当新生代进行垃圾回收的时候,会将所有的伊甸园区域还在使用的对象放在
                From区域,然后将From区域的所有对象全部复制到To区域里,其次将From区域
                和伊甸园区域进行清空,之后将To区域变成From区域,把之前被清空的From区域
                变成To区域,以上流程存活下来的对象的年龄会进行+1操作.
老年代:
    a.经历15次垃圾回收->变成老年代.
    b.如果对象太大,新生代的内存区域装不下这个对象(触发垃圾回收,垃圾回收之后还是装
      不下这个对象,则该对象直接晋级老年代)
    c.一旦新生代对象晋升成老年代,而老年代装不下这个对象的时候,会将老年代中不再使用的
      对象进行垃圾清理,如果老年代清理之后还是装不下这个对象则会抛出异常(OOM->Out of memory
      内存溢出)
永久代:一直都会被使用的,比如元数据(.class文件)
    随着项目越来越大,造成元数据以及.class文件会越来越多,最终会造成永久代可能装不下
    这些数据,也会发生OOM
    解决策略:1.调大永久代的内存区域;2.取消永久代(提出元空间-->堆外内存).

程序计数器

1.记录程序运行到哪儿了

执行引擎

1.用于执行具体的方法和逻辑(运行代码);
2.负责解释jvm内部命令,翻译给操作系统执行.

类加载器

1.作用:将.class文件加载到运行时的数据区域,只进行加载,不进行校验(意思你的类里边
  可能有一些错误,这个类能不能运行起来加载器是不清楚的).
2.分类:
  a.虚拟机自带的加载器:
      启动类加载器(bootstrapClassLoader):
      扩展类加载器(extensionClassLoader):
      应用类加载器(APPClassLoader):
  b.用户自定义加载器:用户可以自定义类的加载方式,写一个类继承java.lang.ClassLoader.
3..class文件的加载顺序:
  首先,.class文件丢给类加载器之后,自定义加载器判断这个类是否被加载过,如果没有
  加载过,则把该类交给应用类加载器,如果已经加载过则立马结束加载;然后应用
  类加载器拿到这个类之后,查看是否加载过,如果已经加载过,则立马结束加载,如果
  没有加载过,则把该类交给扩展类加载器;扩展类加载器拿到这个类之后,查看是否加
  载过,如果已经加载过,则立马结束加载,如果没有加载过,则交给启动类加载器;启动
  类加载器拿到这个类之后,查看是否加载过,如果已经加载过,则立马结束加载,如果没
  有加载过,则尝试加载,如果加载成功,立马结束加载,如果加载失败,则交给扩展类加
  载器;扩展类拿到该类之后尝试加载,如果加载成功,则立马结束加载,如果加载失败,则
  交给应用程序加载器加载;应用程序拿到该类后,尝试加载,如果加载成功,则立马结束
  加载,如果加载失败,则交给自定义类加载器;自定义类加载器拿到该类后,尝试加载,如
  果加载成功,则立马结束加载,如果没有加载成功,则抛出ClassNoFoundException.
4.双亲委派机制
  作用:保证安全,可避免自己编写的类动态替换java的核心类,比如java.lang.String

2.jvm每块作用是什么

4.jvm常用参数(jvm调优)

Young GC->表示只有新生代回收

Full GC->表示既有新生代回收又有老年代回收

5.垃圾回收--算法

6.垃圾回收--工具(垃圾回收器)

JUC

await搭配while而不是if!!!!!!!!!!

线程:1.如何创建线程.2线程同步.3.线程通讯.

1.程序:是为了完成某个特定的任务,而用某种语言编写的一组指令的集合,即指的
  是一段静态的代码,静态对象。

2.进程:是程序的一次执行过程,或是一个正在运行的程序。是一个动态的过程:有它
  自身的产生、存在、和消亡的过程——生命周期。

程序是静态的,进程是动态的。系统在运行时会为每个进程分配不同的内存空间。 

3.线程:进程可进一步细化为线程,是一个程序内部的执行的路径。若一个进程同一时间
  并行执行多个线程,就是支持多线程的。线程作为调度和执行的单位,每个线程拥有独立
  的运行栈和程序计数器(PC),一个进程中的多个线程共享相同的内存单元/内存地址空间,
  可以访问相同的变量和对象,这就使得线程间的通信更简便、高效。但多个线程操作共享
  系统资源可能会带来安全隐患。

sleep和wait的区别

1.sleep是Thread线程类的一个内部的静态方法;

2.wait是Object类中的一个实现方法,是非静态方法;

3.所有的对象都可以进行wait,但是只有线程对象能进行sleep;

4.无论是wait还是sleep都可以被中断;

5.sleep是在指定的时间内线程属于阻塞状态,当时间到了以后,线程苏醒;

6.wait有两种状态:一个是指定时间,一个是不指定时间,当一个对象wait以后,需要其他对象进行notify(随机唤醒    一个wait中的线程)唤醒/notifyAll(唤醒全部处于wait中的线程);

7.sleep不会释放锁资源,wait会释放锁资源.

串行,并发,并行的区别

synchronized关键字

1.修饰的对象:

        a.修饰一个代码块:被修饰的代码块同一时间只能一个人访问;

        b.修饰一个方法;

        c.修饰一个静态的方法;

        d.修饰一个类;

2.情景:一个类中有两个方法a和b,每个方法都加了synchronized关键字.当创建两个线程分别调用这两个方法时,            会不会发生阻塞?

        情况一:当a方法是static的synchronized,b方法是static的synchronized--->>会发生阻塞.

        情况二:当a方法是static的synchronized,b方法不是static的synchronized.-->不会发生阻塞.

        情况三:当a方法不是static的synchronized,b方法也不是static的synchronized.-->会发生阻塞.

锁膨胀过程(jdk对synchronize关键字的优化)

1.我们在堆中创建的对象,会有一个对象头(MarkWord),里边记录着对象的哈希值、年龄(垃圾回收)、锁(线程    id).锁的底层原理即该对象头中的线程id.

2.锁膨胀,其实就是锁的状态发生变化:无锁->偏向锁->轻量级锁->重量级锁  (锁的级别越来越高,加锁解锁消耗    越大)

3.锁的那几个状态怎么理解?

        a.无锁:对象没有线程访问的时候

        b.偏向锁:好比只有一个线程访问对象(核心思想->在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一个线程多次获得,因此为了减少同一个线程获取锁(会涉及到一些CAS操作,很耗时)的代价而引入偏向锁.一旦a线程持有了该对象,标志位修改为1(后边a线程如果连续获得该锁,标志位连续+1),就进入偏向模式,同时会把这个线程的id记录在对象的Mark word中.当a线程再次请求锁时,无需再作任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作,从而提升程序的性能,但对于锁竞争比较激烈的场合,偏向锁就失效了,因为这种场合极有可能每次申请锁的线程都是不同的)

        c.轻量级锁:多线程交替访问对象,不会发生冲突(不存在并发)

        d.重量级锁:多线程存在竞争关系(存在并发).注:重量级锁的时候会产生一个对象监视器指针,它作用于                                  await与notify

注:锁的状态是由竞争升级的,而不是由哪个线程主动选择.而且锁的级别只升不降.当不再有线程进行抢锁的时候,随着事件的推移,会造成锁超时,从而达到锁消失.

锁消除,锁粗化,自旋锁,自适应自旋锁(synchronize知识)

1.锁消除->取消没有意义的锁

 2.锁粗化->没有必要反复的加锁

 3.自旋锁

        当一个线程拿着锁的时候,其他的线程不知道该线程什么时候会释放锁,所以其他线程会陷入一种状态(不         断的来尝试给该对象加锁,而拿到锁的线程长时间不释放锁,就会导致其他线程一直尝试加锁,导致浪费         CPU).

4.自适应自旋锁

        在自旋锁的基础上进行优化->其他线程不再一直尝试加锁,而是尝试相应的次数(比如现在加锁的这个线程         成功加锁前尝试了20次,那么自适应自旋锁就尝试加锁20次,如果都没能加锁,直接进入锁阻塞状态)

Lock接口

lock接口的方法

public interface Lock {
    //加锁: 加锁如果失败会一直尝试,加锁成功还是失败不知道结果
    void lock();
    //中断锁: 加锁必须要成功为止,没有成功就会一直尝试(中断掉)
    void lockInterruptibly() throws InterruptedException;
    //加锁: 加锁就一次,可以知道这次加锁是成功还是失败
    boolean tryLock();
    //加锁: 在指定时间内一直加锁,可以知道这次加锁是成功还是失败
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //释放锁:如果加锁成功,不释放锁,导致死锁
    void unlock();
    //钥匙
    Condition newCondition();
}

Lock锁的可重入锁、公平锁

public class SaleTicketLock {

    private Integer ticket = 100;

    Lock lock = new ReentrantLock();
    //Lock lock = new ReentrantLock(true);如果使用这种方式声明锁,则该lock锁为
    //公平锁,即每个线程依次获得一下该锁

    public void sale(){
        try {
            lock.lock();
            if (ticket>0){
            ticket --;
            System.out.println(Thread.currentThread().getName()+"购买了一张票,还剩"+ticket+"张票");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void sendMessage(){
        try {
            System.out.println(Thread.currentThread().getName()+"is running");
        }finally {

        }
    }

    public static void main(String[] args) {
        SaleTicketLock saleTicketLock = new SaleTicketLock();
            new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
    //解释->当一个线程拿到lock锁执行a对象的加了锁的b()方法之后,又想去执行
    //      a对象的加了锁的c()方法,这个是可以的,当该线程把两个方法都执行完了
    //      之后就会把锁释放掉(可以记为switch的case穿透性)
                saleTicketLock.sale();
                saleTicketLock.sendMessage();
                }
            }).start();
            new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
                saleTicketLock.sale();
                saleTicketLock.sendMessage();
                }
            }).start();
    }
}

读写锁->读锁释放之后写锁才能被抢

public class ReadAndWrite {

    //    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Object data = null;


    public void write(Object data){
        //    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        try {
            writeLock.lock();
            this.data = data;
            System.out.println(Thread.currentThread().getName()+"is writing");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"has writed");
        }
        finally {
            writeLock.unlock();
        }
    }

    public void read(){
        //    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        try {
            readLock.lock();
            System.out.println(Thread.currentThread().getName()+"is reading");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"get the data which is"+this.data);
        }
        finally {
            readLock.unlock();
        }
    }

    public static void main(String[] args) {
        ReadAndWrite readAndWrite = new ReadAndWrite();
        new Thread(() -> {
            readAndWrite.write("image");
        },"徐老师").start();


        for (int i = 0; i < 67; i++) {
            new Thread(() -> {
                readAndWrite.read();

            },"小"+i).start();
        }

    }

}

定制化通信

public class CustomizedCommunication {
    Lock lock = new ReentrantLock();
    Condition cut = lock.newCondition();
    Condition cook = lock.newCondition();
    Condition give = lock.newCondition();

    private String flag = "cut";


    public void cut(){
        try {
            lock.lock();
            while (!flag.equals("cut")){
                try {
                    cut.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"cut");

            this.flag = "cook";
            cook.signal();
        }
        finally {
            lock.unlock();
        }
    }
    public void cook(){
        try {
            lock.lock();
            while (!flag.equals("cook")){
                try {
                    cook.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"cook");

            this.flag = "give";
            give.signal();
        }
        finally {
            lock.unlock();
        }
    }
    public void give(){
        try {
            lock.lock();
            while (!flag.equals("give")){
                try {
                    give.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"give");

            this.flag = "cut";
            cut.signal();
        }
        finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        CustomizedCommunication customizedCommunication = new CustomizedCommunication();
        new Thread(() -> {
            for (int i = 1; i < 11; i++) {
                customizedCommunication.cut();
                System.out.println(Thread.currentThread().getName()+"正在切第"+i+"到菜");
            }
        },"cut").start();
        new Thread(() -> {
            for (int i = 1; i < 11; i++) {
                customizedCommunication.cook();
                System.out.println(Thread.currentThread().getName()+"正在炒第"+i+"到菜");
            }
        },"cook").start();
        new Thread(() -> {
            for (int i = 1; i < 11; i++) {
                customizedCommunication.give();
                System.out.println(Thread.currentThread().getName()+"正在上第"+i+"到菜");
            }
        },"give").start();
    }
}

中断锁

public class LockInterrupt {

    Lock lock = new ReentrantLock();

    public void dateing(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()+"正在约会");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally {
            System.out.println(Thread.currentThread().getName()+"约会完毕");
            lock.unlock();
        }
    }
    public void waiting(){
        System.out.println(Thread.currentThread().getName()+"正在等待");
        try {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            lock.lockInterruptibly();
            System.out.println(Thread.currentThread().getName()+"终于等到你");
            System.out.println(Thread.currentThread().getName()+"正在约会");
            System.out.println(Thread.currentThread().getName()+"约会完毕");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }catch (Exception e){
            System.out.println(Thread.currentThread().getName()+"不等了,滚!");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        LockInterrupt lockInterrupt = new LockInterrupt();
        new Thread(() -> {
            lockInterrupt.dateing();
        },"情敌").start();
        Thread bt = new Thread(() -> {
            lockInterrupt.waiting();
        }, "备胎");
        bt.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bt.interrupt();
    }
}

lock和synchronized作比较

1.相同点.

都支持独占线程,都支持可重入.

2不同点.

lock系列api用法  synchronized用法
加锁/解锁手动自动
支持共享锁√(比如读锁)×
支持尝试获取锁×
支持响应中断×
代码风格面向对象面向过程
底层原理AQS(volatile+CAS+线程的双向链表)=非阻塞同步阻塞同步

程序计数器

1.介绍:通过使用CountDownLatch可以使当前线程阻塞,等待其他线程完成给定任务.可以类比旅游团要等待所有的旅客到齐后才能去下一个景点.CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,构造方法里边就传入N,这里所说的N个点,可以使N个线程,也可以是1个线程里的N个执行步骤.

构造器:

public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
 }

2.注:计数器参数count必须大于等于0,等于零的时候,调用await方法不会阻塞当前线程.

3.当我们调用CountDownLatch的countDown()方法时,N就会减1,CountdownLatch的await()方法会阻塞当前线程,直到N编程0.

4,使用案例:使用多线程下载网络上的图片,下载完成后,提示用户下载完成.

public class MyCountDownLatch {

    public static void main(String[] args) {
        System.out.println("等待旅客集合!!");
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        CountDownLatch countDownLatch = new CountDownLatch(67);
        for (int i = 1; i < 68; i++) {
            new Thread(() -> {
                Random random = new Random();
                int times = random.nextInt(5);
                try {
                    Thread.sleep(times*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("旅客"+Thread.currentThread().getName()+"到达集合点!");
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                countDownLatch.countDown();
            },i+"").start();
        }

        try {
            //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("我是导游,人到齐了,我们去下一个景点!");
    }

}

循环栅栏

public class MyCyclicBarrier {

    public static void main(String[] args) {
        //创建7个线程,每个线程执行完毕下边的7会减1,减到0开始执行
        //下边构造器里边的Runnable重写方法
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("已经集齐七颗龙珠,出来吧神龙!");
        });
        for (int i = 1; i < 8; i++) {
            int num = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"开始收集龙珠");
                Random random = new Random();
                int times = random.nextInt(5);
                try {
                    Thread.sleep(times*1000);
                } 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();
                }
            },i+"").start();
        }
    }
}

信号灯

public class MySemaphore {

    public static void main(String[] args) {
        //创建三个信号灯,
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i < 8; i++) {
            new Thread(() -> {
                try {
                    //线程拿到信号灯即可继续执行
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"号车进入车位");
                int times = new Random().nextInt(7)+1;
                try {
                    Thread.sleep(1000*times);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"号车驶出车位");
                //线程执行完方法归还信号灯
                semaphore.release();
            },i+"").start();
        }
    }
}

创建多线程的实现方式

1.继承Thread类

public class First extends Thread {

    public First(String threadName){
        super(threadName);
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"简单");
    }

    public static void main(String[] args) {
        new First("1").start();
    }
}

2.实现Runnable接口

public class Second implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"easy");
    }

    public static void main(String[] args) {
        Second second = new Second();
        new Thread(second,"2").start();
    }
}

3.线程池

public class Third {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(() -> {
            System.out.println(Thread.currentThread().getName()+"");
        });
    }
}

4.Callable+FutureTask

public class Fourth {
    public static void main(String[] args) {
        FutureTask<BigDecimal> futureTask = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName()+"");
            return new BigDecimal("4");
        });

        new Thread(futureTask,"four").start();
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

5.CompletableFuture->组合式异步编程(异步编排)

CompletableFuture实现了Future接口和CompletionStage接口

future接口提供的方法

get()->调用该方法的线程进行等待,直到等待的任务做完才能执行get()方法以后的代码

cancel()->取消该任务

isCanceled()->判断该任务是否取消,是返回true,不是返回false,

isDone()->查看任务是否以及完成,如果完成了返回true,否则返回false

get(long time,TimeUnit unit)->只等time的时间,如果任务还没执行完则调用该方法的线程继续执行

只有get方法会抛异常.

CompletableFuture自己的静态方法

我们使用CompletableFuture可以直接调用的方法

runAsync()->无返回结果

allof()->所有任务执行完才执行该代码下边的代码,需要join()!!!

anyOf()->任何任务执行完就可以执行改代码下边的代码需要join()!!!

supplyAsync()->有返回结果

CompletionStage提供的方法

!!!!!!不带Async的可能由子线程执行,可能由主线程执行

1.thenRunAsync()->无参无返

2.thenAcceptAsync()->有1参无返,参数为上一步的结果

3.thenApplyAsync()->有1参有返,参数为上一步的结果

4.exceptionally()->有1参有返,参数为上一步抛的异常,如果上一步发生异常才会执行该任务,exceptionally()里边只会打印上一步的异常,而不会因为上一步发生异常而结束任务

5.whenCompleteAsync()->两2参无返,无论有没有异常都会执行,第一个参数:上一步的结果;第二个参数:上一步抛的 异常,当whenCompleteAsync()里边的代码执行完毕就会往外抛异常

6.handleAsync()->2参有返,无论有没有异常都会执行,第一个参数为上一步的结果,第二个参数为上一步的异常,不抛异常

6.Fork Join

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public class ForkJoinTest extends RecursiveTask<Long> {

    private Long start;
    private Long end;
    private Long result = 0L;

    public ForkJoinTest(Long start, Long end){
        this.start = start;
        this.end = end;
    }

    //重写方法
    @Override
    protected Long compute() {
        if (end - start <= 100){
            //表示能算
            System.out.println("已经达到可计算范围"+start+"=========="+end);
            for (Long i = start; i <= end; i++) {
                result = result + i;
            }
        }else {
            //开始拆分任务
            Long leftStart = start;
            Long leftEnd = (start + end)/2;
            Long rightStart = leftEnd + 1;
            Long rightEnd = end;
            //交给新的分组下线
            ForkJoinTest leftForkJoin = new ForkJoinTest(leftStart, leftEnd);
            ForkJoinTest rightForkJoin = new ForkJoinTest(rightStart, rightEnd);

            //启动下线任务
            leftForkJoin.fork();
            rightForkJoin.fork();

            //获得下线结果
            Long leftResult = leftForkJoin.join();
            Long rightResult = rightForkJoin.join();
            //结果
            result = leftResult + rightResult;
        }
        return result;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程池
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTest forkJoinTest = new ForkJoinTest(1L, 98456L);
        //线程池启动任务
        ForkJoinTask<Long> submitResult = forkJoinPool.submit(forkJoinTest);
        //获取分组计算的结果
        Long result = submitResult.get();
        System.out.println("最终结果是"+result);
    }
}

7.并行计算

8.Timer定时任务

9.Spring的一部方法调用

线程池解析

自定义线程池

/**
 *  商品详情微服务使用的线程池
 */
@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8,//核心线程数:
                // 文件IO较多的情况->等于逻辑线程数数量;计算较多的情况->等于逻辑线程数数量*2
                16,//最大线程数
                10,//闲置时间
                TimeUnit.SECONDS,//闲置时间单位
                new ArrayBlockingQueue<>(100),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂对象:用于创建线程
                new ThreadPoolExecutor.AbortPolicy());
        return threadPoolExecutor;//拒绝策略
    }

    /*
    *   线程池的膨胀过程:
    *   1.在项目启动后,会通过springboot包扫描注解扫描到当前配置类,会完成线程池的初始化,并存储到IOC容器中当作一个Bean
    *       线程池中:核心线程数:0个;非核心线程数:0个,阻塞队列中元素:0个
    *   2.这时候来了一个任务需要被执行,将任务分配给线程池,此时线程池开始调用线程执行这个任务
    *       线程池中:核心线程数:1个;非核心线程数:0个,阻塞队列中元素:0个
    *   3.和上面那个任务一起来的还有7个任务,将任务分配给线程池,此时线程池开始调动线程执行这些任务
    *       线程池中:核心线程数:8个(满了);非核心线程数:0个,阻塞队列中元素:0个
    *   4.与上面8个任务一起来的还有8个任务,将任务分配给线程池,此时线程池开始调用线程执行这些任务
    *       线程池中:核心线程数:8个(满了);非核心线程数:0个,阻塞队列中元素:8个
    *   5.与上面8个任务一起来的还有92个任务,将任务分配给线程池,此时线程池开始调用线程执行这些任务
    *       线程池中:核心线程数:8个(满了);非核心线程数:0个,阻塞队列中元素:100个(满了)
    *   6.与上边92个任务一起来的还有12个任务,将任务分配给线程池,此时线程池开始调用线程执行这些任务
    *       线程池中:核心线程数:8个(满了);非核心线程数:8个(满了),阻塞队列中元素:100个(满了)
    *   7.再来任何数量的任务,都会触发拒绝策略:
    *       a:ThreadPoolExecutor.AbortPolicy->抛异常,不执行任务
    *       b:ThreadPoolExecutor.CallerRunsPolicy->执行任务,但是是谁主线程去执行,即提交线程任务的线程
    *       c.ThreadPoolExecutor.DiscardPolicy->不执行任务,啥也不做,丢弃线程
    *       d.ThreadPoolExecutor.DiscardOldestPolicy->出列等待时间最长的那一个,然后丢掉,将新任务交给线程次执行
    * */

    /*
    *   线程池的方法shutdown()和shutdownNow()的区别:
    *   一般情况下,当我们频繁的使用线程的时候,为了解决资源快速相应需求,我们都会考虑使用线程池,
    *   线程池使用完毕之后使用以上两个方法进行关闭,一下列举以上两个方法的区别:
    *       shutdown()->它是将线程池的状态设置为SHUTDOWN状态,不过正在执行的任务会继续执行下去,没有被执行的则中断(不再执行)
    *       shutdownNow()->它是将线程池的状态设置为STOP,正在执行的任务会被停止,没有被执行的也进行中断(不再执行)
    * */

}

JDK=JRE+java开发辅助工具....硬件系统->操作系统->JVM

JRE=JVM+java程序运行时所需要的类库

1.结构

        a.类加载器->加载我们编写的类以及java里边的类到java虚拟机的内存空间,按需加载即第一次使用的时候才加载.只加载不校验正确与否.如果四种加载器都不能加载某个类,则直接ClassNotFindException.

        b.内存区->

                A:程序计数器->相当于执行计划.让CPU进行安全有序的执行.

                B.栈->随着线程的创建而创建,随着线程的消失而消失

                        存储数据:方法形参变量,方法体内声明的变量,方法返回值变量.

                        栈帧结构:局部变量表(保存方法中声明的所有变量),操作数栈(方法运行过程中的临时数据),帧数据区(保存访问常量池指针,异常处理表).

                        父子关系:帧栈通过父子关系可以确定方法的调用关系;子父栈帧形成链表(父帧:指向当前栈针的调用者;子帧:当前栈帧调用的下一个栈帧).

                        栈溢出错误:栈给当前线程分配的空间被占满后,还要申请更多空间.

                        栈线程私有:当某一个线程抛出StackOverflowError不会影响其他线程,因为栈会给每个线程单独分配空间.

                C.堆->线程共享,最大堆大小->计算机内存的四分之一;初始堆大小->计算机内存的六十四分之一.

                D.方法区(永久代)->构造器,方法,static修饰的类变量和常量.线程共享.永久代的内存回收主要针对常量池的回收和类的卸载,因此可回收的对象很少.(常被用来存储常量,静态变量,类信息,类中方法的代码和class文件)

                E.本地方法区->为native方法服务,它从本地方法接口拿到方法进行调用

        c.本地方法接口->像前端调用我们的接口一样,我们也要调用本地方法

           本地方法库->存储本地方法的地方(java中带native的方法)

2.类加载器

        a.Bootstrap启动类加载器->加载$JAVA_HOME$/jre/lib/rt.jar里边的类.,如果我们想使用加载器对象.getParent()  这个方法去获取,是获取不到的,因为它是使用c++编写的.

        b.Extension扩展类加载器->加载$JAVA_HOME$/jre/lib/ext/classes目录里边的类

        c.APPClassLoader应用程序加载器->加载classpath中指定的jar包及目录中的class

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐吉柯德77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值