美文网首页
并发编程和JVM调优

并发编程和JVM调优

作者: 极速魔法 | 来源:发表于2021-01-09 14:42 被阅读0次

并发编程三要素

  • 原子性
  • 有序性
  • 可见性

守护线程和非守护线程

非守护线程运行结束,jvm退出,与守护线程是否存在无关。
守护线程通常用在作为垃圾收集器或缓存管理器的应用程序中,执行辅助任务

Callable 有返回值

package com.lagou.concurrent.demo;

import java.util.concurrent.*;

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

    ThreadPoolExecutor executor = new ThreadPoolExecutor( 5, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10) ) { 
        @Override protected void afterExecute(Runnable r, Throwable t) { 
        super.afterExecute(r, t); 
        } 
    };

    Future<String> future = executor.submit(new MyCallable());

    String s = future.get(); System.out.println(s);

    executor.shutdown();

    }
}

synchronized关键字

给某个对象加锁
实例方法锁加在对象 myClass上;静态方法锁加在 MyClass.class

锁🔐的本质

锁是一个对象

  1. 这个对象内部得有一个标志位(state变量),记录自己有没有被某个线程用。

  2. 如果这个对象被某个线程占用,记录这个线程的thread ID。

  3. 这个对象维护一个thread id list,记录其他所有阻塞的、等待获取拿这个锁的线程。在当前线程释 放锁之后从这个thread id list里面取一个线程唤醒。

轻量级阻塞和重量级阻塞

能够被中断的阻塞称为轻量级阻塞,对应的线程状态是WAITING或者TIMED_WAITING;
而像 synchronized 这种不能被中断的阻塞称为重量级阻塞

Interrupted异常

只有那些声明了会抛出InterruptedException的函数才会抛出异常,
也就是下面这些常用的函数 sleep(),wait(),join()

thread.interrupted()的精确含义是唤醒轻量级阻塞,而不是字面意思“中断一个线程”。如果线程此时恰好处于WAITING 或者TIMED_WAITING状态,就会抛出一个InterruptedException,并且线程被唤醒。

thread.isInterrupted()与Thread.interrupted()的区别

  • thread.isInterrupted() 实例方法,不改变线程中断状态
  • Thread.interrupted() 静态方法,改变线程中断状态,对中断状态取反

并发和并行

并发: 一个cpu核心执行多个任务
并行:不同核心上同时运行多个任务

happen-before

如果A happen-before B,意味着A的执行结果必须对B可见,也就是保证跨线程的内存可见性

CopyOnWrite

CopyOnWrite指在“写”的时候,不是直接“写”源数据,而是把数据拷贝一份进行修改,再通过悲观锁或 者乐观锁的方式写回。
为了在“读”的时候不加锁。

同步工具

Semaphore

信号量,提供了资源数量的并发访问控制

// 5份共享资源。第二个参数表示是否是公平
Semaphore myResources = new Semaphore(5, true);
//工作线程每获取一份资源,就在该对象上记下来
myResources.acquire();

// 工作线程每归还一份资源,就在该对象上记下来
myResources.release();

CountDownLatch

主线程要等待5个 Worker 线程执行完才能退出

CountDownLatch latch = new CountDownLatch(5);

// 子线程中任务完成
latch.countDown();

// 主线程等待 
latch.await();

自旋与阻塞

阻塞:放弃CPU,进入阻塞状态,等待后续被唤醒,再重新被操作系统调度。 自旋:多核cpu,不放弃CPU,空转,不断重试,也就是所谓的“自旋”。

Lock与Condition

“可重入锁”是指当一个线程调用 object.lock()获取到锁,进入临界区后,再次调用object.lock(),仍然可 以获取到该锁。

ForkJoin

RecursiveAction 没有返回值
RecursiveTask<Long>,有返回值。

求1到n个数的和
继承RecursiveTask,重写compute()方法

public class ForkJoinPoolDemo02 {

    static class SumTask extends RecursiveTask<Long> { 
        private static final int THRESHOLD = 10; 
        private long start; 
        private long end;

        public SumTask(long n) { this(1, n); }

        public SumTask(long start, long end) { 
            this.start = start; 
            this.end = end; 
        }

        @Override
        protected Long compute() {
            long sum = 0; 
            // 如果计算的范围在threshold之内,则直接进行计算 
            if ((end - start) <= THRESHOLD) { 
                for (long l = start; l <= end; l++) {
                    sum += l;
                } 
            } else { 
                // 否则找出起始和结束的中间值,分割任务
                long mid = (start + end) >>> 1;

                SumTask left = new SumTask(start, mid);
                SumTask right = new SumTask(mid + 1, end);
                left.fork(); 
                right.fork(); 
                // 收集子任务计算结果 
                sum = left.join() + right.join();
            } 
            return sum;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException { 
        SumTask sum = new SumTask(100); 
        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask<Long> future = pool.submit(sum);

        Long aLong = future.get(); 
        System.out.println(aLong); 
        pool.shutdown();
    }
}

JVM

JVM与操作系统

JVM 与操作系统之间的关系:JVM 上承开发语言,下接操作系统,它的中间接口就是字节码

JVM 内存

JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分

线程私有的: ①程序计数器 ②虚拟机栈 ③本地方法栈
线程共享的: ①堆 ②方法区 直接内存(非运行时数据区的一部分)

虚拟机栈

Java虚拟机栈和线程同时创 建,用于存储栈帧
每个方法在执行时都会创建一个栈帧(Stack Frame), 用于存储局部变量表、操作数栈、动态 链接、方法出口等信息。

唯一目的就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。在内存中不连续
设置堆空间大小

-Xmx20m -Xms5m
当下Java应用最大可用内存为20M, 最小内存为5M

永久代和元空间

  1. 存储位置不同:永久代在物理上是堆的一部分,和新生代、老年代的地址是连续的,而元空间属于本地内存。

  2. 存储内容不同:在原来的永久代划分中,永久代用来存放类的元数据信息、静态变量以及常量池等。 现在类的元信 息存储在元空间中,静态变量和常量池等并入堆中,相当于原来的永久代中的数据,被元空间和堆内存给瓜分了。

常量池和运行时常量池

字节码文件中,内部包含了常量池
方法区中,内部包含了运行时常量池
常量池:存放编译期间生成的各种字面量与符号引用
运行时常量池:常量池表在运行时的表现形式

JVM加载机制

类加载器ClassLoader角色

  1. class file 存在于本地硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到 JVM当中来根据这个文件实例化出n个一模一样的实例。
  2. class file 加载到JVM中,被称为DNA元数据模板。
  3. 在 .class文件 --> JVM --> 最终成为元数据模板,此过程就要一个运输工具(类装载器Class Loader),扮演一 个快递员的角色。Class对象存放在方法区

类使用的阶段

类从被加载到虚拟机内存中开始,到卸载出内存,
它的整个生命周期包括:
加载(Loading)、验证 (Verification)、
准备(Preparation)、解析(Resolution)、初始化(Initiallization)、使用(Using)和卸载 (Unloading)这7个阶段

初始化

<clinit> 由Javac编译器的 自动生成物
执行类变量的赋值动作和静态语句块(static{}块) 中的 语句

  • 父类的clinit()方法先执行
  • 执行接口的 clinit()方法不需要先执行父接口的()方法,
    只有当父接口中定义的变量被使用 时, 父接口才会被初始化。
    此外, 接口的实现类在初始化时也 一样不会执行接口的clinit()方法。
  • 多个线程同 时去初始化一个类, 那 么只会有其中一个线程去执行这个类的()方法, 其他线程都需要阻塞等 待, 直到活动线程执行完毕clinit()方法

垃圾回收

垃圾回收算法

判断对象生死算法

  • 引用计数法
  • 可达性分析算法

收集死亡对象方 法

有四种,如标记-清除算法、标记-复制算法、标记-整理算法。

垃圾收集器

垃圾收集器是算法的落地实现


image

相关文章

  • 并发编程和JVM调优

    并发编程三要素 原子性 有序性 可见性 守护线程和非守护线程 非守护线程运行结束,jvm退出,与守护线程是否存在无...

  • 美团 Java 面试 154 道题分享!

    Java集合22题 JVM与调优21题 并发编程28题 spring 25题 设计模式 10题 springboo...

  • Java进阶架构之架构筑基面试题:JVM+Netty+并发编程

    架构筑基 Java程序性能优化 JVM性能调优 Linux基础与进阶 Mysql Tomcat 并发编程进阶 高性...

  • JVM调优

    1 调优层次 性能调优包含多个层次,比如:架构调优、代码调优、JVM调优、数据库调优、操作系统调优等。架构调优和代...

  • 3.JVM调优工具

    JVM调优工具 1、JVM调优工具-JDK工具 1.1 jps jps:Java Virtual Machine ...

  • java面试要求

    了解JVM运行机制,熟练JVM调优,了解内存管理熟悉大流量、高并发、高性能系统架构设计和研发了解大规模系统的负载均...

  • JVM调优高频面试

    JVM调优目的 使用较小的内存占用来获得较高的吞吐量或者较低的延迟。 一、JVM内存调优 对JVM内存的系统级调优...

  • 调优进阶

    什么是调优? 根据需求进行JVM规划和预调优 优化运行JVM运行环境(慢,卡顿) 解决JVM运行过程中出现的各种问...

  • Spark(十八)JVM调优之原理概述以及降低cache操作的内

    一、调优背景 1、常规性能调优:分配资源、并行度。。。等 2、JVM调优(Java虚拟机):JVM相关的参数,通常...

  • 2019-10-12 jvm调优

    JVM调优总结

网友评论

      本文标题:并发编程和JVM调优

      本文链接:https://www.haomeiwen.com/subject/mducaktx.html