Java面经自用5
-
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()); } }
-
通过线程池来开启线程
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
-
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; } }
-
java线程锁机制是怎样的?偏向锁,轻量级锁,重量级锁有什么区别?锁机制如何升级?
锁,就是在对象的Markword中记录一个锁状态。无锁,偏向锁,轻量级锁,重量级锁都会对应不同的锁状态,锁机制就是根据资源竞争的激烈程度不断进行锁升级的过程
偏向锁:线程过来登记信息后可去访问
轻量级锁:自旋锁,失败重试,浪费cpu,一直等待锁释放后成功获取锁 volatile
重量级锁:需要和操作系统交互,效率低 synchronized
new对象的时候,jvm会进行优化有两个参数
-XX:UseBiasedLocking 是否打开偏向锁,默认不打开
-XX:BiasedLockingStartupDelay 4秒后打开偏向锁
-
谈谈你对AQS的理解。AQS如何实现可重入锁?
1.AQS是JAVA线程同步的框架。JDK中几乎所有的锁都是基于AQS实现的
2.在AQS中,维护了一个信号量state=0,加锁线程=null和一个线程组成的双向链表队列
线程1获取锁state=1后CAS判断是否获取成功,成功后加锁线程=线程1,线程2则进入等待队列,线程1锁释放后state递减,加锁线程变为null,从等待队列中取出线程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()依次操作
- 如何对一个字符串快速进行排序?(Fork/Join框架)
分而治之,拆分再汇总
将大的任务分成若干个小的task放入任务列表,后join计算,调度cpu线程资源,尽量多的使用cpu核心数,将大的任务拆分成很多的小的子任务
-
TCP和UDP有什么区别?TCP为什么是三次握手,而不是两次?
TCP:一种面向连接的,可靠的,传输层通讯协议 点对点的通讯,效率低,占用资源比较多
UDP:一种无连接的,不可靠的,传输层通讯协议 发送方不管接收方有没有准备好,直接发送。广播发送,传输不可靠可能丢失消息,效率高,占用资源比较少
2.如果网络不稳定会造成发送失败,资源浪费的情况
-
java中有几种io模型?有什么区别?
同步异步针对请求,阻塞非阻塞针对客户端
BIO 同步阻塞io 可靠性差,吞吐量低,适用于连接少比较固定的场景
NIO 同步非阻塞io 可靠性比较好,吞吐量比较高,适用于连接多并且连接短的场景 例如聊天室
AIO 异步非阻塞io 可靠性是最好的,吞吐量高,适用于连接多,连接时间长的场景 例如相册服务器 编程模型简单,需要操作系统支持
-
java nio的核心组件?分别有什么作用?
Channel Buffer Selector
channel 类似于流 每个channel对应一个buffer缓冲区。channel会注册到selector ,selector会根据channel上的读写事件将其交给某个空闲的线程处理selector必然对应一个或者多个线程
buffer和selector都是可读可写
-
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.不同的安全级别证书的费用也不同
-
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 ,就会被标记为垃圾,然后清理掉
- jvm有哪些垃圾回收器?他们都是怎么工作的?什么是stw?他都发生在哪些阶段?什么是三色标记?如何解决错标记和漏标记的问题?为什么设计这么多的垃圾回收器?
stw:stop the world ,是在垃圾回收算法执行过程中,需要将jvm内存冻结的一种状态。在stw状态状态下,java的所有线程都是停止的除了GC线程,native方法可以执行,但是不能与jvm交互。
GC各种算法的优化的重点就是减少stw,这也是jvm调优的重点
CMS核心算法是三色标记
三色标记:是逻辑上的一种抽象,将内存对象分为三种颜色 黑色:表示自己和成员变量都已经标记完毕。灰色: 自己标记完了,但是成员变量还没有完全标记完。白色:自己未标记完
cms通过增量标记 increment update 的方式来解决漏标问题
- 如何进行jvm调优?jvm参数有哪些?怎么查看一个进程的jvm参数?谈谈你对jvm参数的理解。如果一个java程序每次运行一段时间后,就变得非常卡顿,如何进行优化?
jvm调优:通过定制jvm运行参数来提高java应用程度的运行数据
利用arths进行排查