java基础题目总结

有些基础题目由于工作中用的比较少但却又是不可少的,这样回答起来就会反应慢,不确定,不准确,特此开了文章记录遇到的不确定或者回答比较拗口的问题。

1.servlet是单例的吗,是安全的吗,是多线程吗

servlet是单例的,根据web.xml实例化一次后,其他访问通过多线程的方式调用servlet实例。 因此,关于多线程访问共享变量的安全性问题已经是老生常谈了。这里只要知道servlet是单例的,其他问题也就解决了。servlet的实现方式决定了安全性。成员变量是否是静态的,是否上锁?关于调用成员变量的方法中是否上锁?或者是否是使用封装在线程内的局部变量?

2.什么是线程安全?常用的HashMap,ArrayList是否安全?

线程安全问题的重点还是共享变量的问题,想了解关于共享变量的变化就要了解jmm(java memory model),简单的说就是线程有工作区,变量放在内存堆中。线程工作必须copy一个副本到工作区去工作,这个操作叫做读取。线程工作结束后将结果写入内存。当多个线程读和写的时候就会有顺序性问题。jvm的中读写无序性使得变量的实际值不确定,每个线程得到的变量的值在于它读取的时候,而之后的时间内改变也不影响线程自己知道的值,即可见性问题。jvm中线程的工作区是互相不可见的。正是因为线程读和写是分两步进行的,在这之间会发生的其他操作造成最终结果的不准确,这就是不安全的原因:原子性。只有保证读写操作是原子的才能保证变量的准确性,于是就是线程同步,即上锁。可以使用synchronized和Lock,还有volatile。 HashMap和ArrayList不是线程安全的。可以使用并发包concurrent下的ConcurrentHashMap,此类采用分段写锁提高并发性,保证写的安全性。同样CopyOnWriteArrayList通过写时上锁并创建副本,在副本写入后,通过volatile规则使得其他线程可见以及缓存一致性,使得其他线程中的副本失效。

3.谈谈对java内存模型的了解

java memory model,jmm. 和上个问题差不多,主要是变量的存储和赋值问题。在上篇文章的volatile有描述。 首先,java对变量的操作:读取,计算,赋值都是在线程中实现的,变量是放在主内存(即内存),而计算的操作必须放在线程的工作区中(对应到硬件就是L1,L2以及寄存器)。线程之间的工作区只有线程自己持有,其他线程无法访问也看不到。这是jmm对可见性的封装。线程根据计算的时间不同而无法保证确切的写入内存的时间,即“无序写入”。java通过上锁来保证原子操作,即原子性。java允许编译器和处理器对指令进行重新排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。,java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够保证的有序性,这个通常也成为happens-before原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么她们就不能保证有序性,虚拟机可以随意地对她们进行重新排序。

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
  • 锁定规则:一个unlock操作先行发生于后面对同一个锁lock操作。
  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。
  • 传递规则:如果操作a线程发生于操作b,而操作b又先行发生于操作c,则可以得出操作a先行发生于操作c。
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个操作。
  • 线程中断规则:对于线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断时间的发生。
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始
  • 这8条原则摘自《深入理解java虚拟机》。前4条规则是比较重要,后4条显而易见。

 4.volatile有什么用?能否用一句话说明下volatile的应用场景?

详细见volatile。 volatile能保证可见性和一定的有序性。由于线程只在自己的工作区工作,如果另一个线程修改了变量的值,其他线程如果需要再次读取变量的值的时候必须从主存中读取。也就是说无法改变已经读取了的线程,但保证了可见性和相对的有序性。另外,jvm的规则:volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。这个可以保证语句的先后执行顺序。代码中volatile标记的操作之前的代码必须执行完毕后才可执行。 应用场景:状态标记量,用作线程run的条件,如果不用volatile则可能会不读取内存标记,或者不知道何时读取。代码顺序保证,volatile标记的变量的操作之前的代码必须执行完毕。double check,双重检查。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏芋道源码1024

【死磕Java并发】—– J.U.C之AQS:CLH同步队列

此篇博客所有源码均来自JDK 1.8 在上篇博客【死磕Java并发】-----J.U.C之AQS:AQS简介中提到了AQS内部维护着一个FIFO队列,该队列就是...

3644
来自专栏老马说编程

(65) 线程的基本概念 / 计算机程序的思维逻辑

在之前的章节中,我们都是假设程序中只有一条执行流,程序从main方法的第一条语句逐条执行直到结束。从本节开始,我们讨论并发,在程序中创建线程来启动多条执行流,并...

2077
来自专栏JAVA技术zhai

干货:Java多线程详解(内附源码)

2194
来自专栏老马说编程

(69) 线程的中断 / 计算机程序的思维逻辑

本节主要讨论一个问题,如何在Java中取消或关闭一个线程? 取消/关闭的场景 我们知道,通过线程的start方法启动一个线程后,线程开始执行run方法,run...

1799
来自专栏Android 研究

Android Handler机制1之Thread

每一个进程都有自己的独立的一块内存空间、一组资源系统。其内部数据和状态都是完全独立的。进程的优点是提高CPU的运行效率,在同一个时间内执行多个程序,即并发执行。...

742
来自专栏程序猿DD

死磕Java并发:J.U.C之AQS:CLH同步队列

在上篇文章“死磕Java并发:J.U.C之AQS简介”中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列。

642
来自专栏积累沉淀

Python快速学习第十一天--Python多线程

Python中使用线程有三种方式: 方法一:函数式 调用thread模块中的start_new_thread()函数来产生新线程。语法如下: thread...

1949
来自专栏编程

Java并发编程:概念和原理

. Java并发编程在实际的工作中应用广泛,有时候需要通过多线程去异步做一些事情,有时候需要通过多线程提升一个任务执行的效率。最近又在回顾一些Java编程的基本...

1836
来自专栏java学习

面试题16(以下java程序输出什么?)

以下java程序输出什么? public class HelloSoGou { public static synchronized void main(St...

2934
来自专栏chenssy

【死磕Java并发】—–J.U.C之AQS:CLH同步队列

此篇博客所有源码均来自JDK 1.8 在上篇博客【死磕Java并发】—–J.U.C之AQS:AQS简介中提到了AQS内部维护着一个FIFO队列,该队列就是CLH...

3118

扫码关注云+社区