java面试题总结系列(多线程)
什么是进程,什么是线程?
进程是操作系统分配资源的最小单元,线程是操作系统调度的最小单元。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。线程包含在进程当中,是进程中实际运行单位。
java实现多线程的几种方式,应该使用哪种方式比较好?
(1)继承 java.lang.Thread 类
(2)实现 java.lang.Runnable 接口
如果你要继承其他类,最好实现Runnable。
Thread类中的Start() 和run() 方法的区别?
start()方法是用来启动新创建的线程,而start()内部调用的run(),如果直接调用run(),则是在原来的线程中运行的。
Runnable和Callable有什么不同?
Callable的 call() 方法可以返回值和抛出异常,而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。
Runnable可以作为Thread构造器的参数,通过开启新的线程来执行,也可以通过线程池来执行。而Callable只能通过提交给线程池ExecutorService执行。
CountDownLatch、CyclicBarrier和Semaphore
1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。
2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。
为什么wait, notify 和 notifyAll这些方法不在thread类里面?
JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。
谈谈你对乐观锁和悲观锁的区别
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号,CAS等机制来实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
谈谈你对ThreadLocal的理解
ThreadLocal是线程的局部变量,是每一个线程所单独持有的,其他线程不能访问。
关于ThreadLocalMap<ThreadLocal, Object>弱引用问题
当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。
虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用,所以为了防止此类情况的出现,我们有两种手段。
1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;
2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。
volatile关键字的作用
1.保证此变量对所有的线程的可见性
2.禁止指令重排序优化
volatile 性能:volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
