synchronized [ˈsɪŋkrənaɪzd] v.同步 35. 并行和并发有什么区别? 36. 进程和线程的区别? 37. 守护线程是什么? 38. 建立线程有哪几种方式? 39. 说一下 runnable 和 callable 有什么区别? 40. 线程有哪些状态? 41. sleep() 和 wait() 有什么区别? 42. notify()和 notifyAll()有什么区别? 43. 线程的 run()和 start()有什么区别? 44. 建立线程池有哪几种方式? 45. 线程池都有哪些状态? 46. 线程池中 submit()和 execute()方法有什么区别? 47. 在 java 程序中怎么保证多线程的运行安全?(synchronized,happens-before原则) 48. 多线程锁的升级原理是什么? 49. 什么是死锁? 50. 怎么防止死锁?(死锁的四个必要条件) 51. ThreadLocal 是什么?有哪些使用场景? 52.说一下 synchronized 底层实现原理? 53. synchronized 和 volatile 的区别是什么? 54. synchronized 和 Lock 有什么区别? 55. synchronized 和 ReentrantLock 区别是什么? 56. 说一下 atomic 的原理?
多线程java
35. 并行和并发有什么区别?程序员
因此并发编程的目标是充分的利用处理器的每个核,以达到醉高的处理性能。算法
36. 进程和线程的区别?编程
简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个或多个线程。进程在执行过程当中拥有独li的内存单元,而多个线程共享内存资源,减小切换次数,从而效率更高。线程是进程的一个实体,同一进程中的多个线程之间能够并发执行,是cpu调度和分派的基本单位,是比程序更小的能独li运行的基本单位。缓存
37. 守护线程是什么?安全
守护线程(即daemon thread),是个服务线程,准确地来讲就是服务其余的线程,这是它的做用——而其余的线程只有一种,那就是用户线程。因此java里线程分2种,
一、守护线程,好比垃圾回收线程,就是最典型的守护线程。
二、用户线程,就是应用程序里的自定义线程。
当全部非守护线程结束时,没有了被守护者,守护线程也就没有工做可作了,也就没有继续运行程序的必要了,程序也就终止了,同时会傻死全部守护线程。 也就是说,只要有任何非守护线程还在运行,程序就不会终止。多线程
38. 建立线程有哪几种方式?并发
①. 继承Thread类建立线程类app
public class FirstThreadTest extends Thread { int i=0 //重写run方法,run方法的方法体就是线程执行体 public void run() { for (; i < 100; i++) { System.out.println(getName() + ":" + i); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { //Thread.currentThread()方法返回当前正在执行的线程对象。 //GetName()方法返回调用该方法的线程的名字。 System.out.println(Thread.currentThread().getName() + ":" + i); if (i == 50) { //建立Thread子类的实例,即建立了线程对象 new FirstThreadTest().start(); new FirstThreadTest().start(); } } }
②. 经过Runnable接口建立线程类异步
public class RunnableThreadTest implements Runnable{ private int i; public void run(){ for(i = 0;i <100;i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } public static void main(String[] args) { for(int i = 0;i < 100;i++) { System.out.println(Thread.currentThread().getName()+":"+i); if(i==20){ //建立 Runnable接口实现类的实例 RunnableThreadTest rtt = new RunnableThreadTest(); new Thread(rtt,"新线程1").start(); new Thread(rtt,"新线程2").start(); } } } }
③. 经过Callable和Future建立线程
package com.nf147.Constroller; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableThreadTest implements Callable<Integer> { public static void main(String[] args) { CallableThreadTest ctt = new CallableThreadTest(); FutureTask<Integer> ft = new FutureTask<>(ctt); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " 的循环变量i的值" + i); if (i == 20) { new Thread(ft, "有返回值的线程").start(); } } try { System.out.println("子线程的返回值:" + ft.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } //重写call()方法,该call()方法将做为线程执行体,而且有返回值 @Override public Integer call() throws Exception { int i = 0; for (; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } return i; } }
建立线程的三种方式的对比
采用实现Runnable、Callable接口的方式建立多线程时,优点是:
线程类只是实现了Runnable接口或Callable接口,还能够继承其余类。
在这种方式下,多个线程能够共享同一个目标对象,因此很是适合多个相同线程来处理同一份资源的状况,从而能够将CPU、代码和数据分开,造成清晰的模型,较好地体现了面向对象的思想
39. 说一下 runnable 和 callable 有什么区别?
有点深的问题了,也看出一个Java程序员学习知识的广度。
40. 线程有哪些状态?
线程一般都有五种状态,建立、就绪、运行、阻塞和死亡。
41. sleep() 和 wait() 有什么区别?
sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其余线程,等到休眠时间结束后,线程进入就绪状态和其余线程一块儿竞争cpu的执行时间。由于sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,可是对象的机锁没有被释放,其余线程依然没法访问这个对象。
wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其余线程可以访问,能够经过notify,notifyAll方法来唤醒等待的线程
42. notify()和 notifyAll()有什么区别?
43. 线程的 run()和 start()有什么区别?
每一个线程都是经过某个特定Thread对象所对应的方法run()来完成其操做的,方法run()称为线程体。经过调用Thread类的start()方法来启动一个线程。
start()方法来启动一个线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,能够直接继续执行下面的代码; 这时此线程是处于就绪状态, 并无运行。 而后经过此Thread类调用方法run()来完成其运行状态, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。而后CPU再调度其它线程。
run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 若是直接调用run(),其实就至关因而调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,因此执行路径仍是只有一条,根本就没有线程的特征,因此在多线程执行时要使用start()方法而不是run()方法。
44. 建立线程池有哪几种方式?
①. newFixedThreadPool(int nThreads)
建立一个固定长度的线程池,每当提交一个任务就建立一个线程,直到达到线程池的最达数量,这时线程规模将再也不变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。
②. newCachedThreadPool()
建立一个可缓存的线程池,若是线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增长时,则能够自动添加新线程,线程池的规模不存在任何限zhi。
③. newSingleThreadExecutor()
这是一个单线程的Executor,它建立单个工做线程来执行任务,若是这个线程异常结束,会建立一个新的来替代它;它的特色是能确保依照任务在队列中的顺序来串行执行。
④. newScheduledThreadPool(int corePoolSize)
建立了一个固定长度的线程池,并且以延迟或定时的方式来执行任务,相似于Timer。
45. 线程池都有哪些状态?
线程池有5种状态:Running、ShutDown(中止)、Stop、Tidying(整理)、Terminated(终止)。
线程池在 ShutDown 状态,任务队列为空且执行中任务为空,线程池就会由 ShutDown 转变为 TIDYING 状态。
线程池在 Stop 状态,线程池中执行中任务为空时,就会由 Stop 转变为 Tidying 状态。
46. 线程池中 submit()和 execute()方法有什么区别?
47. 在 java 程序中怎么保证多线程的运行安全?
线程安全在三个方面体现:
解决办法:
Happens-Before 规则以下:
48. 多线程锁的升级原理是什么?
在Java中,锁共有4种状态,级别从低到高依次为:无锁,偏向锁,轻量级锁和重量级锁状态,这几个状态会随着竞争状况逐渐升级。锁能够升级但不能降级。
无锁:没有对资源进行锁定,全部的线程都能访问并修改同一个资源,但同时只有一个线程能修改为功,其余修改失败的线程会不断重试直到修改为功。
偏向锁:对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续的执行中自动获取偏向锁,指的就是偏向第1个加锁线程,该线程是不会主动释放偏向锁的,只有当其余线程尝试竞争偏向锁才会被释放。
偏向锁的撤销,须要在某个时间点上没有字节码正在执行时,先暂停拥有偏向锁的线程,而后判断锁对象是否处于被锁定状态。若是线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁;
若是线程处于活动状态,升级为轻量级锁的状态。
轻量级锁:轻量级锁是指当锁是偏向锁的时候,被第2个线程 B 所访问,此时偏向锁就会升级为轻量级锁.
线程 B 会经过自旋的形式尝试获取锁,线程不会阻塞,从而提升性能。当前只有一个等待线程,则该线程将经过自旋进行等待。
可是当自旋超过必定的次数时,轻量级锁便会升级为重量级锁;当一个线程已持有锁,另外一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。
重量级锁:指当有一个线程获取锁以后,其他全部等待获取该锁的线程都会处于阻塞状态。操做系统实现线程之间的切换须要从用户态切换到内核态,切换成本很是高。
锁升级的图示过程:
49. 什么是死锁?
死锁是指两个或两个以上的进程在执行过程当中,因为竞争资源或者因为彼此通讯而形成的一种阻塞的现象,若无外力做用,它们都将没法推动下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。是操做系统层面的一个错误,是进程死锁的简称,最先在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操做系统乃至整个并发程序设计领域最难处理的问题之一。
50. 怎么防止死锁?
死锁的四个必要条件:
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不知足,就不会发生死锁。
理解了死锁的缘由,尤为是产生死锁的四个必要条件,就能够尽量地避免、预防和 解除死锁。
因此,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确 定资源的合理分配算法,避免进程永jiu占据系统资源。
此外,也要防止进程在处于等待状态的状况下占用资源。所以,对资源的分配要给予合理的规划。
51. ThreadLocal 是什么?有哪些使用场景?
Java提供ThreadLocal类来支持线程局部变量,是一种实现线程安全的方式。任何线程局部变量一旦在工做完成后没有释放,Java 应用就存在内存泄露的风险。
threadlocal而是一个线程内部的存储类,能够在指定线程内存储数据,数据存储之后,只有指定线程能够获得存储数据
大体意思就是ThreadLocal提供了线程内存储变量的能力,这些变量不一样之处在于每个线程读取的变量是对应的互相独li的。经过get和set方法就能够获得当前线程对应的值。
ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不一样的点是
52.说一下 synchronized 底层实现原理?
synchronized能够保证方法或者代码块在运行时,同一时刻只有一个方法能够进入到临界区,同时它还能够保证共享变量的内存可见性。
Java中每个对象均可以做为锁,这是synchronized实现同步的基础:
jvm基于进入和退出Monitor对象来实现方法同步和代码块同步
这里要注意:
public class SynchronizedDemo { public synchronized void f(){ //为方法加锁 System.out.println("Hello world"); } public void g(){ synchronized (this){ //为代码块加锁 System.out.println("Hello world"); } } public static void main(String[] args) { } }
53. synchronized 和 volatile 的区别是什么?
volatile([ˈvɑːlətl] adj.不稳定的)
54. synchronized 和 Lock 有什么区别?
55. synchronized 和 ReentrantLock 区别是什么?
synchronized是和if、else、for、while同样的关键字,ReentrantLock是类,这是两者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,能够被继承、能够有方法、能够有各类各样的类变量,ReentrantLock比synchronized的扩展性体如今几点上:
另外,两者的锁机制其实也是不同的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操做的应该是对象头中mark word。
56. 说一下 atomic 的原理?
Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操做时,具备排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程能够向自旋锁同样,继续尝试,一直等到执行成功。
Atomic系列的类中的核心方法都会调用unsafe类中的几个本地方法。咱们须要先知道一个东西就是Unsafe类,全名为:sun.misc.Unsafe,这个类包含了大量的对C代码的操做,包括不少直接内存分配以及原子操做的调用,而它之因此标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患,须要当心使用,不然会致使严重的后果,例如在经过unsafe分配内存的时候,若是本身指定某些区域可能会致使一些相似C++同样的指针越界到其余进程的问题。