Java面经自用5

Java面经自用5

  1. java如何开启线程?怎么保证线程安全?

    线程和进程的区别:进程是操作系统进行资源分配的最小单元。线程是操作系统进行任务分配的最小单元,线程隶属于进程

    如何开启线程?

    1.继承Thread,重写run方法

    2.实现Runnable接口,重写run方法

    3.实现Callable接口,实现call方法。通过FutureTask创建一个线程,获取到线程执行的返回值

    class myth implements Callable<Integer> {
    
        @Override
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName()+"====="+"我叼你妈的");
            return 1024;
        }
    }
    
    public class mythread {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            FutureTask<Integer> task = new FutureTask<>(new myth());
            FutureTask<Integer> task2 = new FutureTask<>(new myth());
            new Thread(task, "AA").start();
            new Thread(task, "BB").start();
    
            System.out.println(task.get());
        }
    }
    
    1. 通过线程池来开启线程

      public class myDiyThreadPool {
          public static void main(String[] args) {
              System.out.println(Runtime.getRuntime().availableProcessors());
              ThreadPoolExecutor pool = new ThreadPoolExecutor(
                      2, 5, 1L, TimeUnit.SECONDS,
                      new LinkedBlockingQueue<Runnable>(3),
                      Executors.defaultThreadFactory(),
                      new ThreadPoolExecutor.CallerRunsPolicy()
              );
              try {
                  for (int i = 1; i <= 10; i++) {
      //                pool1.execute(new Thread() {
      //                    @Override
      //                    public void run() {
      //                        System.out.println();
      //                    }
      //                });
      //                最大线程池为5+3=8,但是10个请求则报错
                      pool.execute(() -> {
      //                只有五个线程去执行
                          System.out.println(Thread.currentThread().getName()+"执行业务");
                      });
      
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  pool.shutdown();
              }
          }
      }
      

怎么保证线程安全?加锁。1.使用jvm提供的锁,synchronized2.JDK提供的各种锁Lock

  1. Volatile和synchronized有什么区别?Volatile能不能保证线程安全?DCL(双端检索机制)单例为什么要加Volatile?

    1.volatile只能保证变量的可见性,不能保证原子性以及禁止指令重排,通常适用于一个线程写多个线程读的情况

    synchronized关键字用来加锁

    2.volatile只能保证线程可见性,不能保证原子性

    3.防止指令重排(1.cpu从内存中读数据,2.内存再返回给cpu,3.cpu内部进行运算,由于cpu运算速度很快执行完1操作,2操作响应时间过长系统优化让其在这个间隙执行3操作后再去执行2操作,就叫做指令重排)

    比如对象创建的过程:

    1.分配内存 2.对象初始化 3.建立指针对应关系 线程不安全的话会进行指令重排(1,2,3,)顺序打乱

    public class danli {
    
        private static volatile danli obj = null;
    
        private danli() {
            System.out.println("大家好我是" + Thread.currentThread().getName());
        }
    
        public static danli getObj() {
            if (obj == null) {
                synchronized (danli.class) {
                    if (obj == null) {
                        obj = new danli();
                    }
                }
            }
            return obj;
        }
    }
    
  2. java线程锁机制是怎样的?偏向锁,轻量级锁,重量级锁有什么区别?锁机制如何升级?

    锁,就是在对象的Markword中记录一个锁状态。无锁,偏向锁,轻量级锁,重量级锁都会对应不同的锁状态,锁机制就是根据资源竞争的激烈程度不断进行锁升级的过程

    偏向锁:线程过来登记信息后可去访问

    轻量级锁:自旋锁,失败重试,浪费cpu,一直等待锁释放后成功获取锁 volatile

    重量级锁:需要和操作系统交互,效率低 synchronized

在这里插入图片描述

在这里插入图片描述

new对象的时候,jvm会进行优化有两个参数

-XX:UseBiasedLocking 是否打开偏向锁,默认不打开

-XX:BiasedLockingStartupDelay 4秒后打开偏向锁

  1. 谈谈你对AQS的理解。AQS如何实现可重入锁?

    1.AQS是JAVA线程同步的框架。JDK中几乎所有的锁都是基于AQS实现的

    2.在AQS中,维护了一个信号量state=0,加锁线程=null和一个线程组成的双向链表队列

    线程1获取锁state=1后CAS判断是否获取成功,成功后加锁线程=线程1,线程2则进入等待队列,线程1锁释放后state递减,加锁线程变为null,从等待队列中取出线程2(可以重入,多次加锁,多次释放锁,加锁次数=释放锁次数)

  2. 有ABC三个线程,如何保证三个线程同时执行?依次执行?有序交错执行?

    并发工具:CountDownLatch(倒数),CylinBarrier(栅栏),Semaphore(信号)

    同时执行:

    newCountDownLatch(1).await();

    有序执行

    class bean {
    
        private Lock lock = new ReentrantLock();
        private Condition c1 = lock.newCondition();
        private Condition c2 = lock.newCondition();
        private Condition c3 = lock.newCondition();
    
        public void print(int number) {
            lock.lock();
            if (number == 1) {
                for (int i = 1; i <= 5; i++) {
                   System.out.println(Thread.currentThread().getName() + "==" + i);
                }
                c2.signal();
                try {
                    c3.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (number == 2) {
                for (int i = 1; i <= 10; i++) {
                   System.out.println(Thread.currentThread().getName() + "==" + i);
                }
                c3.signal();
                try {
                    c1.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (number == 3) {
                for (int i = 1; i <= 15; i++) {
                   System.out.println(Thread.currentThread().getName() + "==" + i);
                }
                c1.signal();
                try {
                    c2.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    public class condition {
        public static void main(String[] args) {
            bean b = new bean();
    
            new Thread("A") {
                @Override
                public void run() {
                    for (int i = 1; i <= 10; i++) {
                        b.print(1);
                    }
                }
            }.start();
            new Thread("B") {
                @Override
                public void run() {
                    for (int i = 1; i <= 10; i++) {
                        b.print(2);
                    }
                }
            }.start();
            new Thread("C") {
                @Override
                public void run() {
                    for (int i = 1; i <= 10; i++) {
                        b.print(3);
                    }
                }
            }.start();
        }
    }
    

    有序交错执行:

    Semaphore实现和上述代码相似 s1,s2,s3 s1.acquire()执行完后s2.release(),s2开始s2.acquire()依次操作

    1. 如何对一个字符串快速进行排序?(Fork/Join框架)

    在这里插入图片描述

    分而治之,拆分再汇总

    将大的任务分成若干个小的task放入任务列表,后join计算,调度cpu线程资源,尽量多的使用cpu核心数,将大的任务拆分成很多的小的子任务

  3. TCP和UDP有什么区别?TCP为什么是三次握手,而不是两次?

    TCP:一种面向连接的,可靠的,传输层通讯协议 点对点的通讯,效率低,占用资源比较多

    UDP:一种无连接的,不可靠的,传输层通讯协议 发送方不管接收方有没有准备好,直接发送。广播发送,传输不可靠可能丢失消息,效率高,占用资源比较少

    2.如果网络不稳定会造成发送失败,资源浪费的情况

  4. java中有几种io模型?有什么区别?

    同步异步针对请求,阻塞非阻塞针对客户端

在这里插入图片描述

BIO 同步阻塞io 可靠性差,吞吐量低,适用于连接少比较固定的场景

在这里插入图片描述

NIO 同步非阻塞io 可靠性比较好,吞吐量比较高,适用于连接多并且连接短的场景 例如聊天室

在这里插入图片描述

AIO 异步非阻塞io 可靠性是最好的,吞吐量高,适用于连接多,连接时间长的场景 例如相册服务器 编程模型简单,需要操作系统支持

  1. java nio的核心组件?分别有什么作用?

    Channel Buffer Selector

    channel 类似于流 每个channel对应一个buffer缓冲区。channel会注册到selector ,selector会根据channel上的读写事件将其交给某个空闲的线程处理selector必然对应一个或者多个线程

    buffer和selector都是可读可写

在这里插入图片描述

  1. HTTP和HTTPS的区别

    HTTP:是互联网上应用最为广泛的网络通讯协议,基于TCP,可以使浏览器更为高效

    HTTPS:是HTTP加强版,可以认为是HTTP+SSL,在HTTP的基础上增加了一系列的安全机制。一方面保证数据传输安全。另一方面对访问者增加了验证机制。是目前最为安全的解决方案

    区别:

    ​ 1.HTTP的连接是简单无状态的,HTTPS的数据传输是经过证书加密的,安全性更高

    ​ 2.HTTP免费,HTTPS需要证书需要收费

    ​ 3.HTTP端口80,Https端口443

    HTTPS缺点:

    ​ 1.HTTPS握手协议费时,会影响到服务的响应速度

    ​ 2.HTTPS也不是完全安全的,证书体系也不是完全安全的。并且HTTPS在面对DDOS(大量访问服务器,很多次的验证)攻击时,几乎起不到作用。

    ​ 3.不同的安全级别证书的费用也不同

  2. JAVA类加载的全过程是怎样的?什么是双亲委派机制?一个对象从加载到jvm,再被gc清理,都经历了什么?

JAVA类加载器:APPCLASSLOADER,EXTCLASSLOADER,BOOTSTRAP CLASSLOADER

每种类加载器都有自己的加载目录,去加载目录下的jar包

每个类加载器对加载过得类都有一个缓存

在这里插入图片描述

向上委托查找,向下委托加载 作用:保护java底层的类不会被应用程序覆盖

类加载过程:加载->连接->初始化

加载:把java的字节码数据加载到jvm内存中,并映射成jvm认可的数据结构

连接:1.验证:检查加载到的字节信息是否符合jvm规范 2.准备:创建类或者接口的静态变量,并赋初始值 半初始化状态 3.解析:把符号引用转为直接引用

初始化:

一个对象从加载到jvm,再被gc清理,都经历了什么?

1.用户创建一个对象,jvm先去方法区去找对象的类型信息,然后创建对象

2.jvm要实例化一个对象,首先要在堆中创建一个对象。半初始化状态

3.对象首先会分配在堆内存中的新生代EDEN区,然后经历一次Minor GC ,对象如果存活,就进入s区,在后续中如果对象一直存活,就会在s区来回拷贝,每移动一次,年龄加1(年龄最大15)超过一定年龄后对象转入老年代

4.当方法执行结束后,栈中的指针会先移除掉

5.堆中的对象,经过fullgc ,就会被标记为垃圾,然后清理掉

  1. jvm有哪些垃圾回收器?他们都是怎么工作的?什么是stw?他都发生在哪些阶段?什么是三色标记?如何解决错标记和漏标记的问题?为什么设计这么多的垃圾回收器?

stw:stop the world ,是在垃圾回收算法执行过程中,需要将jvm内存冻结的一种状态。在stw状态状态下,java的所有线程都是停止的除了GC线程,native方法可以执行,但是不能与jvm交互。

GC各种算法的优化的重点就是减少stw,这也是jvm调优的重点

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CMS核心算法是三色标记

三色标记:是逻辑上的一种抽象,将内存对象分为三种颜色 黑色:表示自己和成员变量都已经标记完毕。灰色: 自己标记完了,但是成员变量还没有完全标记完。白色:自己未标记完

cms通过增量标记 increment update 的方式来解决漏标问题

  1. 如何进行jvm调优?jvm参数有哪些?怎么查看一个进程的jvm参数?谈谈你对jvm参数的理解。如果一个java程序每次运行一段时间后,就变得非常卡顿,如何进行优化?

jvm调优:通过定制jvm运行参数来提高java应用程度的运行数据

在这里插入图片描述
利用arths进行排查

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值