concurrenthashmap为何读不用加锁
jdk1.7
1)HashEntry中的key、hash、next均为final型,只能表头插入、删除结点
2)HashEntry类的value域被声明为volatile型
3)不允许用null作为键和值,当读线程读到某个HashEntry的value域的值为null时,便知道产生了冲突——发生了重排序现象(put设置新value对象的字节码指令重排序),需要加锁后重新读入这个value值
4)volatile变量count协调读写线程之间的内存可见性,写操作后修改count,读操作先读count,根据happen-before传递性原则写操作的修改读操作能够看到
jdk1.8
1)Node的val和next均为volatile型
2)tabAt和casTabAt对应的unsafe操作实现了volatile语义
3.ContextClassLoader(线程上下文类加载器)的作用
越过类加载器的双亲委派机制去加载类,如serviceloader实现
使用线程上下文类加载器加载类,要注意保证多个需要通信的线程间的类加载器应该是同一个,防止因为不同的类加载器导致类型转换异常(ClassCastException)
tomcat类加载机制
不同应用使用不同的webapp类加载器,实现应用隔离的效果,webapp类加载器下面是jsp类加载器
不同应用共享的jar包可以放到Shared类加载器/shared目录下
osgi类加载机制
osgi类加载模型是网状的,可以在模块(Bundle)间互相委托
osgi实现模块化热部署的关键是自定义类加载器机制的实现,每个Bundle都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换
当收到类加载请求时,osgi将按照下面的顺序进行类搜索:
1)将以java.*开头的类委派给父类加载器加载
2)否则,将委派列表名单(配置文件org.osgi.framework.bootdelegation中定义)内的类委派给父类加载器加载
3)否则,检查是否在import-Package中声明,如果是,则委派给Export这个类的Bundle的类加载器加载
4)否则,检查是否在Require-Bundle中声明,如果是,则将类加载请求委托给required bundle的类加载器
5)否则,查找当前Bundle的ClassPath,使用自己的类加载器加载
6)否则,查找类是否在自己的Fragment Bundle中,如果在,则委派给Fragment Bundle的类加载器加载
7)否则,查找Dynamic import-Package(Dynamic import只有在真正用到此Package的时候才进行加载)的Bundle,委派给对应Bundle的类加载器加载
8)否则,类查找失败
如何结束一个一直运行的线程
使用退出标志,这个flag变量要多线程可见
使用interrupt,结合isInterrupted()使用
threadlocal使用场景及问题
threadlocal并不能解决多线程共享变量的问题,同一个threadlocal所包含的对象,在不同的thread中有不同的副本,互不干扰
用于存放线程上下文变量,方便同一线程对变量的前后多次读取,如事务、数据库connection连接,在web编程中使用的更多
问题:注意线程池场景使用threadlocal,因为实际变量值存放在了thread的threadlocalmap类型变量中,如果该值没有remove,也没有先set的话,可能会得到以前的旧值
问题:注意线程池场景下的内存泄露,虽然threadlocal的get/set会清除key(key为threadlocal的弱引用,value是强引用,导致value不释放)为null的entry,但是最好remove
以上就是长沙牛耳教育java培训机构的小编针对“互联网常见Java编程面试题”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。
Java面试题