Java知识回忆录(三)——多线程
作者:互联网
1.多线程的几种实现方式,什么是线程安全。
1.继承Thread类。2.实现Runnable接口(实现Runnable接口,然后将它传递给Thread的构造函数,创建一个Thread对象;二是直接继承Thread类。)
2.volatile的原理,作用,能代替锁么。
volatile只具备synchronized的可见性,不具备其原子性
Volatile利用内存栅栏机制(内存屏障)来保持变量的一致性。不能代替锁
参看:http://blog.csdn.net/gongzi2311/article/details/20715185
3.画一个线程的生命周期状态图。
线程的生命周期状态。新建(new)、可运行(runnable)、运行中(running)、休眠(sleep)、阻塞()、等待(wait)、死亡
4.sleep和wait的区别。
sleep是休眠线程,wait是等待。
sleep是Thread类的静态方法,wait是Object类的方法。
调用sleep时,依然持有锁,调用wait时会释放锁。
wait notify notifyall只能使用在同步控制块中。
5.sleep和sleep(0)的区别。
sleep(0),当线程调度器的可运行队列中存在已就绪并且优先级高于当前线程的就绪线程,则线程调度器会移除当前线程,调度其他优先级高的线程运行。如果不存在,则当前线程继续运行。
sleep(timeout),当前线程休眠指定时间(timeout)。
SwitchToThread() 方法,如果当前有其他就绪线程在线程调度器的可运行队列中,始终会让出一个时间切片给这些就绪线程,而不管就绪线程的优先级的高低与否。
6.Lock和Synchronized的区别。
两者都保持了并发场景下的原子性和可见性,区别则是synchronized的释放锁机制是交由其自身控制,且互斥性在某些场景下不符合逻辑,无法进行干预,不可人为中断等。
而lock常用的则有ReentrantLock和readwritelock两者,添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。
用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而是用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内!!
参看:https://blog.csdn.net/vking_wang/article/details/9952063
7.synchronized的原理是什么,一般用在什么地方(比如加在静态方法和非静态方法的区别,静态方法和非静态方法同事执行的时候会有影响吗?),解释以下名称:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。
Synchronized底层是通过监视器的mointorenter和mointorexit实现
ReentrantLock 和synchronized 都是 可重入锁
可重入锁最大的作用是避免死锁(一个同步方法调用另一个同步方法)
参看:https://my.oschina.net/cnarthurs/blog/847801
参看:http://blog.csdn.net/a314773862/article/details/54095819
8.用过哪些原子类,他们的原理是什么。
AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean;基于CAS原语实现 ,比较并交换、加载链接/条件存储,最坏的情况下是旋转锁
参看:https://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html
9.JUC下研究过哪些并发工具,讲讲原理。
10.说明线程池的原理,说明newCache和newFixed有什么区别,构造函数的各个参数的含义是什么,比如coreSize,maxSize。
newSingleThreadExecutor,创建一个包含单线程的Executor,将多个任务交个这个Executor执行,一个任务一个任务的执行,当出现异常时,将会有一个新的线程来代替。
newCachedThreadPool根据用户的任务数创建相应的线程来处理,该线程池不会对线程数目加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。
newFixedThreadPool创建指定数量的线程来执行任务,如果线程数量小于任务数量,则没有被执行的任务进行等待,直到有任务被执行完才执行。
coreSize:核心线程数、maxSize:最大线程数。
11.线程池的关闭方式有几种,各自的区别是什么。
Shutdown shutdownNow tryTerminate 清空工作队列,终止线程池中各个线程,销毁线程池
参看:http://ifeve.com/java-threadpoolexecutor/
12.假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多10个线程同时调用它,如何做到。
ScheduledThreadPoolExecutor 是一个可以实现定时任务的 ThreadPoolExecutor(线程池)
13.spring的controller是单例还是多例,怎么保证并发安全。
单例
通过单例工厂 DefaultSingletonBeanRegistry实现单例
通过保AsyncTaskExecutor持安全
14.用三个线程按顺序循环打印abc三个字母,比如abcabcabc。
1.线程池。2.join()方法
15.ThreadLocal的用途是什么,原理是什么,用的时候注意什么。
ThreadLocal:线程本地变量,用于提供线程内的局部变量,用于公共变量之间的信息传递。
ThreadLocal底层通过threadlocalMap实现,将线程ID作为Key,实列对象作为Value存入Map中。(key指向threadlocal为弱引用,垃圾回收机制看见就回收)。
使用完之后要进行remove();操作不然会导致内存泄漏,因为弱引用引用的对象被回收之后,key变为null,对应的value再也取不到了。
16.如果让你实现一个并发安全的链表,你会怎么做。
Collections.synchronizedList() ConcurrentLinkedQueue;
参看:http://blog.csdn.net/xingjiarong/article/details/48046751
17.有哪些无锁数据结构,他们的实现原理是什么。
LockFree,CAS
基于jdk提供的原子类原语实现,例如AtomicReference
http://blog.csdn.net/b_h_l/article/details/8704480
18.讲讲java同步机制的wait和notify。
这两个方法只能在同步代码块中调用,wait会释放掉对象锁,等待notify唤醒。
1. notify唤醒一个线程,如果有多线程在wait,可能是随机一个
2. notifyAll唤醒所有在等待的线程,
3. 使用中尽量使用notifyAll,因为notify容易导致线程死锁(nofity只唤醒一个,其他等待的线程没有唤醒)
19.CAS机制是什么,如何解决ABA问题。
CAS:Compare and Swap,当一个变量值需要更新时,只有当变量的预期值和内存中实际值相同时才更新。(乐观锁,不断的尝试读取更新)
ABA问题:增加标识符(如添加版本号等)
20.多线程如果挂住了怎么办。
根据具体情况(sleep,wait,join等),酌情选择notifyAll,notify进行线程唤醒。
http://blog.chinaunix.net/uid-122937-id-215913.html
21.countdownlatch和cyclicbarrier的内部原理和用法,以及相互之间的差别(比如countdownlatch的await方法和是怎么实现的)。
22.对AbstractQueuedSynchronizer了解多少,讲讲加锁和解锁的流程,独占锁和公平锁加锁有什么不同。
23.使用synchronized修饰静态方法和非静态方法有什么区别。
修饰静态方法加锁对象为类对象,修饰非静态方法加锁对象为实列对象
24.简述ConcurrentLinkedQueue和LinkedBlockingQueue的用处和不同之处。
LinkedBlockingQueue 是一个基于单向链表的、范围任意的(其实是有界的)、FIFO 阻塞队列。
ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。它采用了“wait-free”算法来实现,该算法在Michael & Scott算法上进行了一些修改, Michael & Scott算法的详细信息可以参见参考资料一。
http://ifeve.com/concurrentlinkedqueue/
http://ifeve.com/juc-linkedblockingqueue/
http://blog.csdn.net/xiaohulunb/article/details/38932923
25.导致线程死锁的原因可能有哪些,怎么解除线程死锁。
死锁问题是多线程特有的问题,它可以被认为是线程间切换消耗系统性能的一种极端情况。在死锁时,线程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是系统任务永远无法执行完成。死锁问题是在多线程开发中应该坚决避免和杜绝的问题。
一般来说,要出现死锁问题需要满足以下条件:
1. 互斥条件:一个资源每次只能被一个线程使用。
2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3. 不剥夺条件:线程已获得的资源,在未使用完之前,不能强行剥夺。
4. 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
只要破坏死锁 4 个必要条件之一中的任何一个,死锁问题就能被解决。
26.非常多个线程(可能是不同机器),相互之间需要等待协调才能完成工作。怎么设计这种协调方案。
此问题的本质是保持顺序执行。可以使用executors
27.读写锁的原理是什么,一般在什么情况下使用。
28.开启多个线程,如果保证顺序执行,有哪几种实现方式,或者如何保证多个线程都执行完在获取结果。
1.join()方法(子线程join和主线程join)、2.通过倒数计时器CountDownLatch实现、3.Java实现生产者消费者的方式。wait和notify\notifyall、4.使用线程的Condition(条件变量)方法、5.使用CyclicBarrier(回环栅栏)实现线程按顺序运行、6.使用Sephmore(信号量)实现线程按顺序运行
参看:https://www.cnblogs.com/wenjunwei/p/10573289.html
29.延迟队列的实现方式,delayQueue和时间轮算法的异同。
标签:回忆录,Java,http,死锁,线程,sleep,net,多线程,wait 来源: https://blog.csdn.net/m0_38024435/article/details/104634253