Java 学习内容总结
最近对Core Java基础做了一些学习。有自己的见解,也有别人的总结,供大家参考。
1 实现多线程的方式有几种?
其实这个问题并不难,只是在这里做一个总结。一共有三种。
- 实现
Runnable
接口,并实现该接口的run()
方法 - 继承
Thread
类,重写run()
方法 - 实现
Callable
接口,实现call()
方法。
大家可能对前两种已经很清楚了,重点说下第三种。
Callable
接口是属于Executor
框架中的类,Callable
接口与Runnable
接口类似,但比后者功能更加强大,主要有三点:
Callable
可以在任务结束后提供一个返回值,Runnable
无法提供这个功能;Callable
的call()
方法可以抛出异常,Runnable
接口的run()
方法不能抛出异常;- 运行
Callable
可以得到一个Future
对象,Future
对象表示异步计算的结果。它提供了检查计算是否完成的方法。由于线程属于异步计算模型,所以无法从其他线程中得到方法的返回值。在这种情况下,就可以使用Future
来监视目标线程调用call()
方法的情况。当调用Futrue
的get()
方法以获取结果时,当前线程就会阻塞,直到call()
方法结束返回结果。
举个例子,此代码在JDK 8 下运行,因为使用了lambda表达式:
package exam;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
// 启动线程
Future<String> future = threadPool.submit(() -> "Hello, world");
try {
System.out.println("waiting thread to finish.");
System.out.println(future.get()); // 等待线程结束,并获取返回结果
threadPool.shutdown();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
2 volatile
关键字的作用
在Java语言中,有时候为了提高程序的运行效率,编译器会做一些优化操作,把经常被访问的变量缓存起来,程序在读取这个变量的时候又有可能直接从寄存器中读取这个值,而不会去内存中读取。这样的好处提高了程序的运行效率,但当遇到多线程编程时,变量的值可能被其他线程改变了,而该缓存的值不会做相应的改变,从而导致应用程序读取的值可能与实际的变量值不一致。关键字volatile
正好解决这个问题,被volatile
修饰的变量编译器不会做优化,每次都会从内存读取。
3 代码中不同属性和方法的执行顺序
经常会遇到一个这样的代码,new一个子类,其子类以及父类每个属性和方法的执行顺序,具体可以看以下例子:
**
* Java程序初始化工作可以在许多不同的代码中来完成,它们执行的顺序如下:
* 父类静态变量
* 父类静态代码块
* 子类静态变量
* 子类静态代码块
* 父类非静态变量
* 父类非静态代码块
* 父类构造函数
* 子类非静态变量
* 子类非静态代码块
* 子类构造函数
*
*
* 注意,只有方法具有多态性,属性则没有。
* @author TurtusLi
*
*/
class BaseI {
int num = 1;
public BaseI() {
this.print();
num = 2;
}
public void print() {
System.out.println("Base.num = " + num);
}
}
public class Example1423 extends BaseI {
int num = 3;
public Example1423() {
this.print();
num = 4;
}
// 去掉这个复写方法,运行看效果
@Override
public void print() {
System.out.println("Sub.num = " + num);
}
public static void main(String[] args) {
BaseI b = new Example1423();
System.out.println(b.num);
}
}
4 switch
语句支持String
类型的实现原理
在Java 7 以后,switch
语句可以用作String
类型上。
从本质来讲,switch
对字符串的支持,其实也是int
类型值的匹配。它的实现原理如下:
通过对case
后面的String
对象调用hashCode(
)方法,得到一个int类型的Hash值,然后用这个Hash值来唯一标识着这个case
。
那么当匹配的时候,首先调用这个字符串的hashCode()
方法,获取一个Hash值(int
类型),用这个Hash值来匹配所有的case
,如果没有匹配成功,说明不存在;如果匹配成功了,接着会调用字符串的equals()
方法进行匹配。
由此看出,String
变量不能是null;同时,switch
的case
子句中使用的字符串也不能为null。
5 多线程同步有几种实现方法
Java主要提供了三种实现同步机制的方法。
synchronized
关键字。有两种用法,可以是synchronized
方法和synchronized
代码块。wait
和notify
方法。Lock
。Lock
接口有一个实现类ReentrantLock
,也可以实现多线程的同步。
6 在多线程编程的时候有哪些注意事项
- 如果能用
volatile
代替synchronized
,近可能使用volatile
。因为被synchronized
修饰的方法或代码块在同一时间只能允许一个线程访问,而volatile
没有这个限制,因此使用synchronized
会降低并发量。由于volatile
无法保证原子性操作,因此在多线程的情况下,只有对变量的操作为原子操作的情况下才可以使用volatile
。 - 尽可能减少
synchronized
块内的代码。 - 给每一个线程定义一个名字,这样有利于调试。
- 尽量使用concurrent容器(
ConcurrentHashMap
)来代替synchronized
容器(Hashtable
)。 - 使用线程池来控制多线程的执行。
7 fail-fast 和fail-safe迭代器的区别是什么?
他们的主要区别是fail-safe允许在遍历的过程中对容器的数据进行修改,而fail-fast则不允许。下面分别介绍这两种迭代器的工作原理。
fail-fast:直接在容器上进行遍历,在遍历的过程中,一旦发现容器中的数据被修改了(添加元素、删除或修改元素),就会抛出ConcurrentModificationException
异常导致遍历失败。常见的使用fail-fast的容器有HashMap
和ArrayList
等。
fail-safe:这种遍历是基于容器的克隆。因此,对容器中内容的修改不影响遍历。常见使用fail-safe方式的容器有ConcurrentHashMap
和CopyOnWriteArrayList
。
8 如何能够使JVM中的虚拟机栈、堆内存和方法区发生内存溢出?
关于JVM的知识,有一本非常好的书籍——周志明《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》,里面有非常好的介绍。几乎可以说是Java程序员必读书籍。
虚拟机栈是线程私有的,当创建一个线程时,同时会新建一个虚拟机栈,它描述的是Java方法执行的内存模型。 栈中有一个非常重要的概念——栈帧。栈帧用于保存局部变量表,操作数栈,方法出口等。
其实栈溢出最简单的方式是无限递归。
堆内存是线程共享的,是JVM中内存管理的最大一块内存,它保存所有实例化的对象。
堆内存溢出最简单的方式是不停的new对象,GC来不及回收,直到内存全部耗尽。
方法区也是内存共享的。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区溢出简单的方式是,调用String
类的intern()
方法,此方法如果在堆区找不到已经存在的String
对象的话,就会往方法区中的常量池放一份,然后返回其引用放在堆区。还有一种办法是不停地加载类。
9 在 int i =0; i=i++;
语句中,i=i++
是线程安全的吗?如果不安全,请说明上面操作在JVM中的执行过程,为什么不安全?说出JDK中哪个类能达到以上程序的效果,并且是线程安全且高效的,简述其原理。
语句i=i++
的执行过程:先把i
的值取出来放到栈顶,可以理解为引入了第三方变量k
,此时,k
的值为i
,然后执行自增操作,于是i
的值变为1
,最后执行赋值操作i=k
(自增前的值),因此,执行结束后,i
的值还是0
。从上面的分析得知,i=i++
语句的执行过程是由多个操作组成,它不是原子操作,因此,不是线程安全的。
在Java中,++i
和i++
操作并不是线程安全的,在使用的时候,不可避免地会用到synchronized
关键字。而AtomicInteger
是一个提供原子操作的Integer
类,它提供了线程安全且高效的原子操作,是线程安全的,其底层的原理是利用处理器的CAS(Compare And Swap,比较与交换,一种有名的无锁算法)操作来检测栈中的值是否被其他线程改变,如果被改变,则CAS操作失败。这种实现方法在CPU指令级别实现了原子操作,因此,它比使用synchronized来实现同步效率更高。
Java 学习内容总结的更多相关文章
- java学习内容整理
转自:http://www.cnblogs.com/caoleiCoding/p/6170555.html 首先,我个人比较推崇的学习方法是:先学java前段,也就是HTML,css,js,因为学习j ...
- 第五周Java学习总结(补)
第五周java学习内容(补) 学习内容: File类方法的操作 public String getName() public boolean canRead() public boolean canW ...
- 20155209 2016-2017-2 《Java程序设计》第九周学习总结 ## 教材学习内容总结
教材学习内容总结 JDBC API 允许用户访问任何形式的表格数据,尤其是存储在关系数据库中的数据. 执行流程: •连接数据源,如:数据库. •为数据库传递查询和更新指令. •处理数据库响应并返回的结 ...
- JAVA第十周《网络编程》学习内容总结
JAVA第十周<网络编程>学习内容总结 学习内容总结 1.初听到网络编程四个字可能会觉得很困难,实际上网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据,把数据发送到指定的位置, ...
- # 20145118 《Java程序设计》第4周学习总结 ## 教材学习内容总结
20145118 <Java程序设计>第4周学习总结 教材学习内容总结 本周内容为教材第六.七两张内容. 重点概念: 1.面向对象中,子类继承父类,避免重复的行为定义,是一种简化操作. 2 ...
- 20145118 《Java程序设计》第5周学习总结 教材学习内容总结
20145118 <Java程序设计>第5周学习总结 教材学习内容总结 1.Java中所有错误都会被打包成对象,可以通过try.catch语法对错误对象作处理,先执行try,如果出错则跳出 ...
- 20155328 2016-2017-2 《Java程序设计》 第十周学习内容总结
20155328 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 JAVA和ANDROID开发学习指南 第22章 网络概览 两台计算机用于通信的语言叫做&qu ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- 分享篇——我的Java学习路线
虽然之前我是开发出身,但是我学习的语言是Objective-c,这个语言使用起来范围比较窄,对于自动化学习来说也是无用武之地,所以我自己学习了Java,对于一个有开发经验的人来说学习一门新语言相对来说 ...
随机推荐
- echarts仪表盘如何设置图例(legend)
echarts 图表中经常需要对不同的颜色设置图例标识不同的意义,而仪表盘的指针只存在一个值,如何表示不同颜色的意义,官网配置项并未给出该功能: 不同段的颜色是通过axisLine->lineS ...
- Work Time Manager【开源项目】- 创建自己日志组件 2.0重构
Hello all , 我又回来了 这次我们真是开始来聊聊开源项目里,小而有用的模块或者组件的开发思想. 同时,软件已经更新到1.60的版本了,支持新用户注册,可以不再使用统一的test账户了. 您可 ...
- linux exec操作文件描述符
linux每一个打开文件都会关联一个文件描述符,需要的时候我们可以使用exec命令指定一个大于3的数字作为文件 linux默认文件描述符 每打开一个shell就会打开默认的三个文件描述符描0,1,2, ...
- webuploader插件,我踩得坑
我在目前的公司做的项目要么是原生写法去做项目,要么就是vue+webpack做项目,但是vue这部分只是用了模板template,vue其他的都没用. 有一个项目需要做上传图片的功能,老大扔给我一个插 ...
- 大数据平台搭建-zookeeper集群的搭建
本系列文章主要阐述大数据计算平台相关框架的搭建,包括如下内容: 基础环境安装 zookeeper集群的搭建 kafka集群的搭建 hadoop/hbase集群的搭建 spark集群的搭建 flink集 ...
- PHP完成一个日历
今天我们就用php中的数组合date 做一个日历. 先让我们回顾一下PHP里面的date . 1.时间戳:表示从计算机元年/UNIX纪年(0时区 1970/1/1 00:00:00)到当前事件的秒数. ...
- su与sudo命令的区别
由于su 对切换到超级权限用户root后,权限的无限制性,所以su并不能担任多个管理员所管理的系统. 如果用su 来切换到超级用户来管理系统,也不能明确哪些工作是由哪个管理员进行的操作. 特别是对于服 ...
- 【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- winform控件闪烁问题终极办法
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle ...
- EF查询百万级数据的性能测试--多表连接复杂查询
相关文章:EF查询百万级数据的性能测试--单表查询 一.起因 上次做的是EF百万级数据的单表查询,总结了一下,在200w以下的数据量的情况(Sql Server 2012),EF是可以使用,但是由于 ...