synchronized 和volatile 关键字的作用
volatile 本质是在告诉jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;volatile 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。2)禁止进行指令重排序。
synchronized 则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
1.volatile 仅能使用在变量级别;synchronized 则可以使用在变量、方法、和类级别的
2.volatile 仅能实现变量的修改可见性,并不能保证原子性;synchronized 则可以保证变量的修改可见性和原子性
3.volatile 不会造成线程的阻塞;synchronized 可能会造成线程的阻塞。
4.volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化
对于原子性,需要强调一点,也是大家容易误解的一点:对volatile变量的单次读/写操作可以保证原子性的,但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作。(能保证原子性的:在boolean中 循环的时候 while (!close) 用volatile修饰close,close的一旦改变就会打破循环)
深入理解synchronized:https://blog.csdn.net/javazejian/article/details/72828483
问题:使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现线程安全吗? 不安全 参考:https://blog.csdn.net/seu_calvin/article/details/52370068
wait()和seelp()方法的区别
最大的不同是在等待时wait 会释放锁,而sleep 一直持有锁。wait 通常被用于线程间交互,sleep 通常被用于暂停执行。
sleep():属于Thread类,可以在任何地方使用,必须捕获异常
wait(): 属于Object类,只能在同步方法或同步控制块中用,不需捕获异常,只在while里面使用,不在if里面使用
参考:https://www.cnblogs.com/loren-Yang/p/7538482.html
notify和notifyAll的区别
notify()只会随机唤醒一个睡眠线程,并不一定是我们想要唤醒的线程。
notifyAll(),唤醒所有等待中的线程
开启线程的三种方式
1、继承Thread类,重写run方法。用start方法启动线程
2、实现Runnable接口,实现run方法。用new Thread(Runnable target).start()来启动
3、实现Callable接口
实现Runnable接口优势:
1)适合多个相同的程序代码的线程去处理同一个资源
2)可以避免java中的单继承的限制
3)增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
继承Thread类优势:
1)可以将线程类抽象出来,当需要使用抽象工厂模式设计时。
2)多线程同步
run()和start()方法区别
run()方法只是一个普通的方法调用,不会开启新的线程。
start()会开启新的线程,分配新的资源,真正实现了多线程运行。
在线程的生命周期中,当调用了线程对象的start方法之后,该线程就进入了就绪状态;
线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
线程如何关闭?
1.设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止
2.使用interrupt()方法中断线程
3.使用stop方法强行终止线程(不推荐使用,是不安全的!)
详细介绍:https://blog.csdn.net/xu__cg/article/details/52831127
如何保证线程安全?如何防止线程的内存泄漏?
所谓线程安全无 非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。
https://blog.csdn.net/bigtree_3721/article/details/76039292
http://www.iteye.com/topic/806990
线程死锁的4个条件?死锁的概念,怎么避免死锁
概念:当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
四个必要条件:
1.互斥条件:一个资源每次只能被一个线程使用。
2.请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:线程已获得的资源,在未使用完之前,不能强行剥夺。
4.循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
在并发程序中,避免了逻辑中出现复数个线程互相持有对方线程所需要的独占锁的的情况,就可以避免死锁。
进程和线程的区别
(1)调度:进程是拥有资源的基本单位。,线程是进程调度和分配的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行。
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
详情参考:https://blog.csdn.net/sunhuaqiang1/article/details/52687518
如何控制某个方法允许并发访问线程的个数?
使用Semaphore https://www.cnblogs.com/androidsuperman/p/6349586.html
介绍介绍CMS。CAS介绍 https://www.jianshu.com/p/12192b13990f
什么是线程池?如何使用?什么时候使用线程池?
线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用new 线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。
单个任务处理时间比较短,需要处理的任务数量很大的时候使用。
线程池的好处?为什么要使用线程池?
a:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
b:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
c:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
为什么:https://blog.csdn.net/it_man/article/details/7193727
说说几种常见的线程池及使用场景。 四种线程池
a:newCachedThreadPool
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
- 适用:执行很多短期异步的小程序或者负载较轻的服务器
b:newFixedThreadPool
创建一个指定工作线程数量的线程池
- 适用:执行长期的任务,性能好很多
c:newScheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
- 适用:一个任务一个任务执行的场景
d:newSingleThreadExecutor
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
- 适用:周期性执行任务的场景
线程池都有哪几种工作队列?
怎么理解无界队列和有界队列?
线程池中的几种重要的参数及流程说明。
synchrolzie关键字和Lock的区别你知道吗?为什么Lock的性能好一些?
ConCurrentHashMap实现
推荐一个并发知识写的很全的地址:http://blog.51cto.com/lavasoft/27069
继续更新中.........