目录介绍
- 5.0.0.1 线程池具备什么优势和缺点?为何说开启大量的线程,会下降程序的性能,那么该如何作才能下降性能?
- 5.0.0.3 线程中start和run方法有什么区别?wait和sleep方法的不一样?sleep() 、join()、yield()有什么区别?
- 5.0.0.4 用Java手写一个会致使死锁的程序,遇到这种问题解决方案是什么?那些场景用到了死锁机制?
- 5.0.0.5 ThreadLocal(线程变量副本)这个类的做用是什么?
- 5.0.0.6 什么是线程安全?线程安全有那几个级别?保障线程安全有哪些手段?ReentrantLock和synchronized的区别?
- 5.0.0.7 Volatile和Synchronized各自用途是什么?有哪些不一样点?Synchronize在编译时如何实现锁机制?
- 5.0.0.8 wait()和sleep()的区别?各自有哪些使用场景?怎么唤醒一个阻塞的线程?Thread.sleep(0)的做用是啥?
- 5.0.0.9 同步和非同步、阻塞和非阻塞的概念?分别有哪些使用场景?
- 5.0.1.0 线程的有哪些状态?请绘制该状态的流程图?讲一下线程的执行生命周期流程?线程若是出现了运行时异常会怎么样?
- 5.0.1.1 synchronized锁什么?synchronized同步代码块还有同步方法本质上锁住的是谁?为何?
- 5.0.1.2 Volatile实现原理?一个int变量,用volatile修饰,多线程去操做++,线程安全吗?那如何才能保证i++线程安全?
- 5.0.1.3 CAS原理是什么?CAS实现原子操做会出现什么问题?
- 5.0.1.4 假若有n个网络线程,须要当n个网络线程完成以后,再去作数据处理,你会怎么解决?
- 5.0.1.5 Runnable接口和Callable接口的区别?
- 5.0.1.6 若是提交任务时,线程池队列已满,这时会发生什么?线程调度算法是什么?
- 5.0.1.7 什么是乐观锁和悲观锁?
- 5.0.1.8 线程类的构造方法、静态块是被哪一个线程调用的?同步方法和同步块,哪一个是更好的选择?同步的范围越少越好吗?
- 5.0.1.9 synchonized(this)和synchonized(object)区别?Synchronize做用于方法和静态方法区别?
好消息
- 博客笔记大汇总【15年10月到至今】,包括Java基础及深刻知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,固然也在工做之余收集了大量的面试题,长期更新维护而且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
- 连接地址:https://github.com/yangchong2...
- 若是以为好,能够star一下,谢谢!固然也欢迎提出建议,万事起于忽微,量变引发质变!全部博客将陆续开源到GitHub!
5.0.0.1 线程池具备什么优势和缺点?为何说开启大量的线程,会下降程序的性能,那么该如何作才能下降性能?
-
线程池好处:php
- 1)下降资源消耗;
- 2)提升相应速度;
- 3)提升线程的可管理性。技术博客大总结
-
线程池的实现原理:html
- 当提交一个新任务到线程池时,判断核心线程池里的线程是否都在执行。若是不是,则建立一个新的线程执行任务。若是核心线程池的线程都在执行任务,则进入下个流程。
- 判断工做队列是否已满。若是未满,则将新提交的任务存储在这个工做队列里。若是工做队列满了,则进入下个流程。
- 判断线程池是否都处于工做状态。若是没有,则建立一个新的工做线程来执行任务。若是满了,则交给饱和策略来处理这个任务。
5.0.0.3 线程中start和run方法有什么区别?wait和sleep方法的不一样?sleep() 、join()、yield()有什么区别?
5.0.0.4 用Java手写一个会致使死锁的程序,遇到这种问题解决方案是什么?那些场景用到了死锁机制?
-
死锁是怎么一回事缓存
- 线程A和线程B相互等待对方持有的锁致使程序无限死循环下去。
-
深刻理解死锁的原理安全
- 两个线程里面分别持有两个Object对象:lock1和lock2。这两个lock做为同步代码块的锁;
- 线程1的run()方法中同步代码块先获取lock1的对象锁,Thread.sleep(xxx),时间不须要太多,50毫秒差很少了,而后接着获取lock2的对象锁。这么作主要是为了防止线程1启动一会儿就连续得到了lock1和lock2两个对象的对象锁
- 线程2的run)(方法中同步代码块先获取lock2的对象锁,接着获取lock1的对象锁,固然这时lock1的对象锁已经被线程1锁持有,线程2确定是要等待线程1释放lock1的对象锁的
5.0.0.5 ThreadLocal(线程变量副本)这个类的做用是什么?
-
ThreadLocal即线程变量
- ThreadLocal为每一个线程维护一个本地变量。
- 采用空间换时间,它用于线程间的数据隔离,它为每一个使用该变量的线程提供独立的变量副本,因此每个线程均可以独立地改变本身的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。ThreadLocal的实现是以ThreadLocal对象为键。任意对象为值得存储结构。这个结构被附带在线程上,也就是说一个线程能够根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。
-
ThreadLocal类是一个Map
- ThreadLocal类中维护一个Map,用于存储每个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。
- ThreadLocal在Spring中发挥着巨大的做用,在管理Request做用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。
- Spring中绝大部分Bean均可以声明成Singleton做用域,采用ThreadLocal进行封装,所以有状态的Bean就可以以singleton的方式在多线程中正常工做了。
- 更多详细参考博客:深刻研究java.lang.ThreadLocal类
5.0.0.6 什么是线程安全?线程安全有那几个级别?保障线程安全有哪些手段?ReentrantLock和synchronized的区别?
5.0.0.7 Volatile和Synchronized各自用途是什么?有哪些不一样点?Synchronize在编译时如何实现锁机制?
5.0.0.8 wait()和sleep()的区别?各自有哪些使用场景?怎么唤醒一个阻塞的线程?Thread.sleep(0)的做用是啥?
5.0.0.9 同步和非同步、阻塞和非阻塞的概念?分别有哪些使用场景?
-
同步和非同步
- 同步和异步体现的是消息的通知机制:所谓同步,方法A调用方法B后必须等到方法B返回结果才能继续后面的操做;所谓异步,方法A调用方法B后可以让方法B在调用结束后经过回调等方式通知方法A
-
阻塞和非阻塞
- 阻塞和非阻塞侧重于等待消息时的状态:所谓阻塞,就是在结果返回以前让当前线程挂起;所谓非阻塞,就是在等待时可作其余事情,经过轮询去询问是否已返回结果
5.0.1.0 线程的有哪些状态?请绘制该状态的流程图?讲一下线程的执行生命周期流程?线程若是出现了运行时异常会怎么样?
无限期等待(Waiting):该线程不会被分配CPU执行时间,要等待被其余线程显式地唤醒。如下方法会让线程陷入无限期等待状态:
```
没有设置Timeout参数的Object.wait()
没有设置Timeout参数的Thread.join()
LockSupport.park()
```
- 限期等待(Timed Waiting):该线程不会被分配CPU执行时间,但在必定时间后会被系统自动唤醒。如下方法会让线程进入限期等待状态:
```
Thread.sleep()
设置了Timeout参数的Object.wai()
设置了Timeout参数的Thread.join()
LockSupport.parkNanos()
LockSupport.parkUntil()
```
- 阻塞(Blocked):线程被阻塞。和等待状态不一样的是,阻塞状态表示在等待获取到一个排他锁,在另一个线程放弃这个锁的时候发生;而等待状态表示在等待一段时间或者唤醒动做的发生,在程序等待进入同步区域的时候发生。
- 结束(Terminated):线程已经结束执行
- 绘制该状态的流程图
-
线程若是出现了运行时异常会怎么样?
- 若是这个异常没有被捕获的话,这个线程就中止执行了。另外重要的一点是:若是这个线程持有某个某个对象的监视器,那么这个对象监视器会被当即释放
5.0.1.1 synchronized锁什么?synchronized同步代码块还有同步方法本质上锁住的是谁?为何?
-
synchronized锁什么
- 对于普通同步方法,锁是当前实例对象;
- 对于静态同步方法,锁是当前类的Class对象;
- 对于同步方法块,锁是括号中配置的对象;
- 当一个线程试图访问同步代码块时,它首先必须获得锁,退出或抛出异常时必须释放锁。synchronized用的锁是存在Java对象头里的MarkWord,一般是32bit或者64bit,其中最后2bit表示锁标志位。
-
本质上锁住的是对象。
- 在java虚拟机中,每一个对象和类在逻辑上都和一个监视器相关联,synchronized本质上是对一个对象监视器的获取。当执行同步代码块或同步方法时,执行方法的线程必须先得到该对象的监视器,才能进入同步代码块或同步方法;而没有获取到的线程将会进入阻塞队列,直到成功获取对象监视器的线程执行结束并释放锁后,才会唤醒阻塞队列的线程,使其从新尝试对对象监视器的获取。
5.0.1.2 Volatile实现原理?一个int变量,用volatile修饰,多线程去操做++,线程安全吗?那如何才能保证i++线程安全?
-
volatile的做用和原理
- Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终须要转化为汇编指令在CPU上执行。
- volatile是轻量级的synchronized(volatile不会引发线程上下文的切换和调度),它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另一个线程能读到这个修改的值。
- 因为内存访问速度远不及CPU处理速度,为了提升处理速度,处理器不直接和内存进行通讯,而是先将系统内存的数据读到内部缓存后在进行操做,但操做完不知道什么时候会写到内存。普通共享变量被修改以后,何时被写入主存是不肯定的,当其余线程去读取时,此时内存中可能仍是原来的旧值,所以没法保证可见性。若是对声明了volatile的变量进行写操做,JVM就会想处理器发送一条Lock前缀的指令,表示将当前处理器缓存行的数据写回到系统内存。
-
一个int变量,用volatile修饰,多线程去操做++,线程安全吗
- 技术博客大总结
- 不安全
- 案例代码,至于打印结果就不展现呢
- volatile只能保证可见性,并不能保证原子性。
-
i++实际上会被分红多步完成:
- 1)获取i的值;
- 2)执行i+1;
- 3)将结果赋值给i。
- volatile只能保证这3步不被重排序,多线程状况下,可能两个线程同时获取i,执行i+1,而后都赋值结果2,实际上应该进行两次+1操做。
private volatile int a = 0;
for (int x=0 ; x<=100 ; x++){
new Thread(new Runnable() {
@Override
public void run() {
a++;
Log.e("小杨逗比Thread-------------",""+a);
}
}).start();
}
-
如何才能保证i++线程安全
- 可使用java.util.concurrent.atomic包下的原子类,如AtomicInteger。其实现原理是采用CAS自旋操做更新值。
for (int x=0 ; x<=100 ; x++){
new Thread(new Runnable() {
@Override
public void run() {
AtomicInteger atomicInteger = new AtomicInteger(a++);
int i = atomicInteger.get();
Log.e("小杨逗比Thread-------------",""+i);
}
}).start();
}
5.0.1.3 CAS原理是什么?CAS实现原子操做会出现什么问题?
-
CAS原理是什么
- CAS即compare and swap的缩写,中文翻译成比较并交换。CAS有3个操做数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作。自旋就是不断尝试CAS操做直到成功为止。
-
CAS实现原子操做会出现什么问题
- ABA问题。由于CAS须要在操做之的时候,检查值有没有发生变化,若是没有发生变化则更新,可是若是一个值原来是A,变成,有变成A,那么使用CAS进行检查时会发现它的值没有发生变化,但实际上发生了变化。ABA问题能够经过添加版本号来解决。Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。
- 循环时间长开销大。pause指令优化。
- 只能保证一个共享变量的原子操做。能够合并成一个对象进行CAS操做。
5.0.1.4 假若有n个网络线程,须要当n个网络线程完成以后,再去作数据处理,你会怎么解决?
- 多线程同步的问题。这种状况能够可使用thread.join();join方法会阻塞直到thread线程终止才返回。更复杂一点的状况也可使用CountDownLatch,CountDownLatch的构造接收一个int参数做为计数器,每次调用countDown方法计数器减一。作数据处理的线程调用await方法阻塞直到计数器为0时。
5.0.1.5 Runnable接口和Callable接口的区别?
-
Runnable接口和Callable接口的区别
- Runnable接口中的run()方法的返回值是void,它作的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合能够用来获取异步执行的结果。
- 这实际上是颇有用的一个特性,由于多线程相比单线程更难、更复杂的一个重要缘由就是由于多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候咱们指望的数据是否已经赋值完毕?没法得知,咱们能作的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却能够获取多线程运行的结果,能够在等待时间太长没获取到须要的数据的状况下取消该线程的任务,真的是很是有用。
5.0.1.6 若是提交任务时,线程池队列已满,这时会发生什么?线程调度算法是什么?
-
若是提交任务时,线程池队列已满,这时会发生什么?
- 若是使用的是无界队列LinkedBlockingQueue,也就是无界队列的话,不要紧,继续添加任务到阻塞队列中等待执行,由于LinkedBlockingQueue能够近乎认为是一个无穷大的队列,能够无限存听任务
- 技术博客大总结
- 若是使用的是有界队列好比ArrayBlockingQueue,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,会根据maximumPoolSize的值增长线程数量,若是增长了线程数量仍是处理不过来,ArrayBlockingQueue继续满,那么则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy
-
线程调度算法是什么?
- 抢占式。一个线程用完CPU以后,操做系统会根据线程优先级、线程饥饿状况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。
5.0.1.7 什么是乐观锁和悲观锁?
-
什么是乐观锁和悲观锁?
- 乐观锁:就像它的名字同样,对于并发间操做产生的线程安全问题持乐观状态,乐观锁认为竞争不老是会发生,所以它不须要持有锁,将比较-替换这两个动做做为一个原子操做尝试去修改内存中的变量,若是失败则表示发生冲突,那么就应该有相应的重试逻辑。
- 悲观锁:仍是像它的名字同样,对于并发间操做产生的线程安全问题持悲观状态,悲观锁认为竞争老是会发生,所以每次对某资源进行操做时,都会持有一个独占的锁,就像synchronized,直接上了锁就操做资源。
5.0.1.8 线程类的构造方法、静态块是被哪一个线程调用的?同步方法和同步块,哪一个是更好的选择?同步的范围越少越好吗?
-
线程类的构造方法、静态块是被哪一个线程调用的?
- 线程类的构造方法、静态块是被new这个线程类所在的线程所调用的,而run方法里面的代码才是被线程自身所调用的。
-
举个例子
-
同步方法和同步块,哪一个是更好的选择?
- 同步块,这意味着同步块以外的代码是异步执行的,这比同步整个方法更提高代码的效率。请知道一条原则:同步的范围越小越好。
- 技术博客大总结
-
同步的范围越少越好吗?
- 是的。虽然说同步的范围越少越好,可是在Java虚拟机中仍是存在着一种叫作锁粗化的优化方法,这种方法就是把同步范围变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,天然最经常使用的append()方法是一个同步方法,咱们写代码的时候会反复append字符串,这意味着要进行反复的加锁->解锁,这对性能不利,由于这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,所以Java虚拟机会将屡次append方法调用的代码进行一个锁粗化的操做,将屡次的append的操做扩展到append方法的头尾,变成一个大的同步块,这样就减小了加锁-->解锁的次数,有效地提高了代码执行的效率。
5.0.1.9 synchonized(this)和synchonized(object)区别?Synchronize做用于方法和静态方法区别?
-
synchonized(this)和synchonized(object)区别技术博客大总结
- 其实并无很大的区别,synchonized(object)自己就包含synchonized(this)这种状况,使用的场景都是对一个代码块进行加锁,效率比直接在方法名上加synchonized高一些(下面分析),惟一的区别就是对象的不一样。
-
对synchronized(this)的一些理解
- 1、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程获得执行。另外一个线程必须等待当前线程执行完这个代码块之后才能执行该代码块。
- 2、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另外一个线程仍然能够访问该object中的非synchronized(this)同步代码块。
- 3、尤为关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其余线程对object中全部其它synchronized(this)同步代码块的访问将被阻塞。
- 4、当一个线程访问object的一个synchronized(this)同步代码块时,它就得到了这个object的对象锁。结果,其它线程对该object对象全部同步代码部分的访问都被暂时阻塞。
-
Synchronize做用于方法和静态方法区别
private void test() {
final TestSynchronized test1 = new TestSynchronized();
final TestSynchronized test2 = new TestSynchronized();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
test1.method01("a");
//test1.method02("a");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
test2.method01("b");
//test2.method02("a");
}
});
t1.start();
t2.start();
}
private static class TestSynchronized{
private int num1;
public synchronized void method01(String arg) {
try {
if("a".equals(arg)){
num1 = 100;
System.out.println("tag a set number over");
Thread.sleep(1000);
}else{
num1 = 200;
System.out.println("tag b set number over");
}
System.out.println("tag = "+ arg + ";num ="+ num1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static int num2;
public static synchronized void method02(String arg) {
try {
if("a".equals(arg)){
num2 = 100;
System.out.println("tag a set number over");
Thread.sleep(1000);
}else{
num2 = 200;
System.out.println("tag b set number over");
}
System.out.println("tag = "+ arg + ";num ="+ num2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//调用method01方法打印日志【普通方法】
tag a set number over
tag b set number over
tag = b;num =200
tag = a;num =100
//调用method02方法打印日志【static静态方法】
tag a set number over
tag = a;num =100
tag b set number over
tag = b;num =200
- 在static方法前加synchronized:静态方法属于类方法,它属于这个类,获取到的锁,是属于类的锁。
- 在普通方法前加synchronized:非static方法获取到的锁,是属于当前对象的锁。 技术博客大总结
- 结论:类锁和对象锁不一样,synchronized修饰不加static的方法,锁是加在单个对象上,不一样的对象没有竞争关系;修饰加了static的方法,锁是加载类上,这个类全部的对象竞争一把锁。
其余介绍
01.关于博客汇总连接
02.关于个人博客