线程和进程相关
线程和进程的区别
线程是进程划分的更小的运行单位,最大的不同在于进程是独立的,而线程不是,同一进程里
一个线程挂掉其它的线程可能会受影响。另外就是线程开销小但不利于资源的维护。
java实现多线程的方式
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口(有返回值)
4.使用线程池
如何处理从线程的异常
线程的异常只能自己内部处理,所以处理方法就是给该线程加上一个
异常处理器UncaughtExceptionHandler。
参考:Java捕获线程异常的几种方式
【Java 多线程】Java中主线程如何捕获子线程抛出的异常
守护线程和用户线程
守护线程就是为用户线程保驾护航的,只有当最后一个用户线程结束时,守护线程才会随着JVM一起退出。
线程上下文间的切换
当前线程在执行完CPU时间片切换到另一个线程前会保留自己当前的状态,以便下次再切换回这个线程时,
可以再加载这个线程的状态,这个从 保存到再加载 的过程就是上下文切换。
wait和sleep的区别、共同点
区别:
1.wait释放了锁,而sleep并没有。
2.wait通常用于线程间交互/通信,而sleep用于暂停运行。
3.wait并不会自动唤醒,而是需要别的线程调用同一对象上的notify()/notifyall()方法
而sleep执行完后,线程自动苏醒,或使用wait(long time)超时后自动苏醒。
共同点:
两者都暂停了线程的执行。
线程死锁
线程池相关
为什么使用线程池
提高性能。
因为每次创建和销毁线程都是需要消耗资源的,当线程数达到一定数量时会耗尽CPU和内存资源,同时也会造成GC频繁收集和停顿,这无疑是巨大的性能瓶颈。而线程池中的线程复用就不用频繁创建线程,同时当一段时间的线程未被使用后就会被自动销毁,极大提升了性能。
线程池的核心参数
corePoolSize:核心线程数,定义了最小可以同时运行的线程量,核心线程不会被回收,如果数目不够,
会在执行任务时新建线程。
maximumPoolSize:最大线程数。在线程达到core,然后workQueue满了后,可以继续创建线程(临时线程)。此时可以同时运行的线程量变味了max。
WorkQueue:线程数超过core时,新的任务在队列中等着。
keepAliveTime:max中的临时线程的存活时间。
unit:keep的单位
handle:线程池满了且queue中也塞满了任务后的拒绝策略。
threadFactory:创建线程的工厂类。
有了任务后新建线程的方式:不超过core的任务有几个建几条,超过了先把任务放到queue中等着,queue也满了就建临时线程来处理。
参考你都理解创建线程池的参数吗?
线程池满了会怎么办,四种拒绝策略
抛异常处理(AbortPolicy)、
直接丢弃(DiscardPolicy)、
丢弃队列中最早未被处理的任务(DiscardOldestPolicy)、
将任务分配给当前执行execute方法线程来处理(CallerRunsPolicy)。
ConcurrentHashMap
有没有了解过ConcurrentHashMap?
线程安全的HashMap,底层数据结构也是数组+链表,但value和链表都是用volatile修饰的,还采用了分段锁的方式保证线程的安全。
JDK1.8之后ConcurrentHashMap如何保证线程安全性?(CAS+synchronized)
1.8后使用CAS+synchronized方法来保证,
与JDK1.7相比有那些优化?
线程同步/安全 同步锁
synchronized和lock底层实现··,区别
synchronized底层实现是在JVM层面的。
它的同步代码块使用了monitorenter和monitorexist指令,当锁计数器为0时可以成功获取锁,获取失败当前对象就要阻塞等待直到锁释放。
而同步方法则是使用该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否是同步方法。
lock底层依赖API。
需要lock()和unlock()方法配合try/finally语句块来完成。
区别:
1.synchronized是关键字,锁的是对象或类;而lock是类,锁的是专门的Lock类对象。
··2.lock增加了一下高级功能:等待可中断、可实现公平锁、可实现选择性通知
3.synchronized依赖JVM,lock依赖于API。
4.synchronized的竞争策略是一系列锁膨胀,而lock是加入排队队列(不公平时直接插队)
共同点:
1.都是可重入锁
2.性能已经差不多了。
说到synchronized,说些synchronized加载static关键字前和普通方法前的区别?
加了static说明是静态synchronized,锁的是这个类,是类锁
而加在非static前说明是非静态synchronized,锁的只是这个实例对象,是对象锁。
eg:1.public synchronized A(){};
2.public B(){ synchonized(this)};
3.public static synchonized C(){};
4.public D(){ synchonized(xx.class);
AB都是对象锁,CD都是类锁。
当两个不同线程想访问同一对象的A、B方法时,发生竞争;而如果是访问不同对象的AB时,不会竞争
当两个不同线程想访问同一对象的A、B方法时,发生竞争;而如果是访问不同对象的CD时,也会竞争
但如果是访问同一对象的A/B方法,再同时访问C/D方法,由于类锁和对象锁在不同区域,不会发生竞争。
··为什么需要锁,你知道几种锁
悲观、乐观锁;
公平、不公平锁;
可重入、不可重入锁;
自旋锁、非自旋锁;
··说说CAS
参数有三个:内存位置(v)、预期原值(A)、新值(B)。
思想是:如果V和A相等,那么就更新V为B。
实现:unsafe.java中提供了CAS操作,而原子类大都包含了CAS操作。
缺点:
1.易造成ABA问题(从二进制上看没改变,但语义上已经不是A了),解决:加版本号
2.不能保证代码块的原子性。CAS只能保证一个变量的原子性但不能保证整个代码块的。
3.造成CPU利用率增加。如果循环判断CAS,而线程一直没有获取到状态,那么CPU就一直被占用。
··说说AQS:
AQS是构建锁和同步器的框架。它定义了一个int共享成员变量来表示同步状态,通过内置的FIFO队列来完成获取锁线程的排队工作。获取方式有独占式或共享式。
1.变量用volatile修饰保证线程可见性
2.FIFO队列:同步器有两个节点型应用,一个指向头结点,另一个指向尾结点。未获取到锁的线程会创建节点线程加入到队列尾部。首节点即为获取同步状态成功的节点。首节点释放锁时会唤醒后继节点,后继节点在获取锁成功时会将自己设为首节点。
3.独占式:有且只有一个线程能获取到锁。
共享式:可以多个线程同时获取到锁。
详情参考:深入介绍Java中的锁[原理、锁优化、CAS、AQS]
··synchronized原理,jdk6对他的优化(偏向锁等),JNI,逃逸分析,对象的markword
原理:
synchronized在Java虚拟机中使用监视器锁来实现。每个对象都有一个监视器锁,当监视器锁被占用时就会处于锁定状态。
线程执行一条叫monitorenter的指令来获取监视器锁的所有权。如果此监视器锁的进入数为0,则线程进 入并将进入数设置为1,成为线程所有者。如果线程已经拥有该锁,因为是可重入锁,可以重新进入,则进入数 加1.如果线程的监视器锁被其他线程占用,则阻塞直到此监视器锁的进入数为0时才能进入该锁。 线程执行一条叫monitorexit的指令来释放所有权。执行monitorexit的必须是线程的所有者。每次执行此指令,线程进入数减1,直到进入数为0。监视器锁被释放。 优化: 偏向锁:偏向第一个获得他的线程。也就是说,如果该锁没有被其他线程获取,那么持有偏向锁的线程就不需要同步。 轻量级锁:
说说volatile,说说线程同步,说说JVM线程模型
加了volatile相当于多了个内存屏障,保证了变量的可见性(一经修改其他线程也能看见)、禁止进行指令重排序。
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
java内存模型
synchronize优化、volatile、内存模型
youzhixueyuan.com/thread-inte… www.lagou.com/lgeduarticl… 4cyaw.com/index.php/a… blog.csdn.net/javazejian/…