专栏首页Ryan Miaojava基础题目总结

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 条评论
登录 后参与评论

相关文章

  • Java并发编程:线程池的使用

    Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,...

    Ryan-Miao
  • Java基础之Synchronized原理

    思维导图svg: https://note.youdao.com/ynoteshare1/index.html?id=eb05fdceddd07759b8b8...

    Ryan-Miao
  • java并发编程(4)--线程池的使用

    转载:http://www.cnblogs.com/dolphin0520/p/3932921.html 一. java中的ThreadPoolExecutor...

    Ryan-Miao
  • Java并发编程之线程封闭

    当访问共享变量时,往往需要加锁来保证数据同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程中访问数据,就不需要同步了。这种技术称为线程封闭。在Java语...

    技术训练营
  • 基于Zmq的后台通信模型介绍

    Zmq是一个简单好用的传输组建,使得socket变成更加简洁、高效、高性能。本文主要介绍后台服务实现、多线程任务实现、线程无锁计数实现。

    airingzeng
  • C# 基础知识系列- 12 任务和多线程

    照例一份前言,在介绍任务和多线程之前,先介绍一下异步和同步的概念。我们之间介绍的知识点都是在同步执行,所谓的同步就是一行代码一行代码的执行,就像是我们日常乘坐地...

    程序员小高
  • 大牛带你分析源码,学会正确使用 Java 线程池

    在日常的开发工作当中,线程池往往承载着一个应用中最重要的业务逻辑,因此我们有必要更多地去关注线程池的执行情况,包括异常的处理和分析等。本文主要聚焦在如何正确使用...

    美的让人心动
  • Java 多线程 Thread 和 Runnable

    多线程是并行计算实现的方式, 但是在单cpu中实际上没有真正的并行,只不过是多个任务通过cpu的快速轮转,产生多任务同一时间运行的错觉.而其中的任务就是进程. ...

    用户7625070
  • 一文探讨 RPC 框架中的服务线程隔离

    微服务如今应当是一个优秀的程序员必须学习的一种架构思想,而RPC框架作为微服务的核心,不说读一遍源码吧,起码它的实现原理还是应该知道的。

    kirito-moe
  • java 线程池设计模式

    进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地...

    用户7625070

扫码关注云+社区

领取腾讯云代金券