String类表示的字符串,但是它属于一个类,而不是基本数据类型,虽然像基本数据类型一样使用
==表达式比较的是内存地址
想要判断两个字符串的内容是否相等可以使用String类中提供 equals()方法来完成
通过实例化方式完成的String类赋值 默认不支持常量池,但是可以通过intern()方法手动入池
字符串常量就是String的匿名对象
String实例化方式赋值的时候会存在两个对象 其中一个String类型的匿名对象做为垃圾空间存在
字符串的内容一旦声明则不可改变
1把字符数组准换为 字符串
2把byte数组转换为字符串
可以频繁修改字符串,在实际使用中,一般来说首选使用String来完成,只有在需要频繁小修改字符串的时候才使用StringBuilder 后者StringBuffer
以上两个类除了线程的安全性之外,其他的功能全部一样
str只有改变指向才会变
RunTime属于运行时的操作类,也是JVM运行时需要加载的类
范例:通过RunTime类取得JVM内存信息
在程序以开始输出的时候就已经在使用这个类,属于系统类
范例:取得当前的系统时间
对象在创建的时候,存在构造方法表示对象属性的初始化
per=null;//指向改变成为垃圾对象gc回收相当于c++的析构函数
主要掌握Date类与long类型相互转换的操作
把Date类型格式化为字符串类型 ,格式化的格式由用户给定
把字符串日期格式转换为Date类型格式
java为用户提供的一些数学操作类,其中四舍五入的操作以及PI的定义
数组的工具类,提供了一系列的数组相关的操作方法
Arrays类中提供的方法
--被调用者 :任何对象,任何数组,任何类型(前提有tostring方法)
--作用 :将被调用者以字符串的形式输出
--被调用者:存储着任何对象的数组,对象要自带tostring方法
--作用:将数组中的对象按照对象的tostring方法一个一个输出来
--没有被调用对象,直接使用方法
--作用:若对象自定义了tostring方法,那么按照对象定义的方法输出,若是对象没有重写方法,则按照输出哈希值
Fill();给定数组 为其填充内容
进程:在操作系统的定义中指的是一次命令完整运行
线程是在进程的基础上上进一步划分:打开一个QQ.exe代表启动一个进程,在QQ可以聊天,聊天的同时可以传输文件,并且还可以语音聊天 在一个QQ进程中启动多个线程
例如:打开一个QQ启动一个进程,在QQ上打开聊天 启动一个线程,在打开一个传输数据,又启动一个线程
从以上的结论中可以发现;在一个进程中可以存在多个线程:而线程是可以同时运行的
效率高:可以最大限度的利用CPU的空闲资源,比如一边编辑文档,一边打印文档中的内容
在java中存在两种方式可以完成多线程的使用,第一种方式就是 (继承)Thread类 ,在java中编写多线程程序的时候必须存在一个线程的主体类,而这个主体类只要继承了Thread类就可以完成多线程的功能
使用了start()方法启动了多线程之后,发现定义的3个线程在执行的时候 不是顺序执行了,而是随机的访问CPU的资源,过程为哪个线程先抢到资源哪个线程就先执行 线程的执行是存在随机性的
在主体方法main方法中把复杂的任务2作为一个单独的线程启动,这样就不会影响任务1 月任务3 的执行效率
通过观察start()方法的源码发现:
继续观察源码发现start()方法会调用一个start0()这个方法而这个方法的定义如下
其中出现了native关键字,表示调用本地系统函数
在线程启动的时候,线程会抢占CPU的资源,CPU的资源调度,需要本地操作系统的支持
以上图一定要明白清楚的自己的可以画出来,面试过程中会存在为什么启动一个线程调用是start()方法而不是run()方法
线程的第二种实现方式实现Runnable接口
为什么存在第二种方式,第一种方式继承Thread类有什么不好
最大的问题:java中存在单继承局限,如果一个类继承了Thread类则这个类就没有办法继承别的类
所以为了解决以上的问题,可以使用第二种方式,实现Runnable接口,在接口中没有单继承的局限,一个类可以实现多个接口
观察Thread类的构造方法可以发现 构造方法的参数为Runnable接口对象,也就是说Thread类的构造方法可以接收Runnble接口的对象
在多态中讲过,在接口中一个父接口可以接收所有的子类对象
通过以上的操作就可以把MyThread传入给Thread类 进而通过Thread类中的start()方法启动一个线程
注意:无论何时启动一个线程必须使用Thread类中的start()方法
在多线程的实现中现在已经了两种方式,Thread类与Runnable接口,从代码上来讲肯定首选使用Runnable接口,应为可以很好的避免单继承局限,可以为程序做更多的扩展
通过源码分析过其实Thread类也是实现的Runnable接口,接下来观察一下他们两个的关系
多线程开发的本质其实就是多个线程同时对一个资源的抢占,Thread主要描述的就是线程,资源是通过Runnable接口完成的
利用Lmbda可以简化在面向对象过程中的开发,但是前提是只有一个抽象方法的接口或者类才可以使用
Lambda表达式是JDK1.8的新特性,利用此形式可以实现函数式编程(一个接口或者一个类只存在一个抽象方法) 前提下就可以简化编写方式
Scala 语言中就提供了函数式编程
在面上对象过程中,一直存在的问题,即使编写简单的代码,同样需要进行类的完整定义
// 只存在一个抽象方法
从传统的开发角度上来说实现一个多线程肯定使用Runnable接口,但是Runnable接口有一个缺点:没有返回值
在Jdk1.5之后推出了callable接口可以给一个线程执行完毕反回结果,接下来观察callableji接口的定义
在callable接口内设置了一个泛型操作,其实这个泛型就是规定了需要反回的数据类型
有这个泛型的支持就不会造成向下转型出现错误
//实现线程的业务方法 类似run方法
//通过Thread启动线程之后 可以通过FutureTask存在get方法可以取得call()方法中的返回值
Runnable接口没有返回值, Callable接口可以在执行多线程任务之后返回数据类型
线程的状态:(面试题)
1 任何一个线程对象都是通过Thread类进行封装,调用start()方法进入到就绪状态,就绪状态线程并没有执行
2线程进入到就绪状态之后,等到资源调度,抢到资源的线程先执行,先执行的线程就进入到运行状态
3 线程在执行的过程可能会存在阻塞状态,当用户调用类似sleep或者wait 方法会进入到阻塞状态
4终止状态,当线程执行完毕,或者调用线程的停止的方法线程就会进入到终止状态
所有线程的操作方法基本上都定义在Thread类中
线程的运行状态是不确定,如果在不确定的线程中操作一个线程只能依靠线程的名字,线程的名字是非常重要的概念,在Thread方法中提供有线程的命名与取得的方法
通过以上的三个方法可以完成线程的命名与取得,但是并不能通过以上方法取得线程当前的对象
为线程设置名称和取得名称在以上的代码中直接在main方法输出当前线程的名称输出为main说明main方法也是一个线程 在JVM启动的时候会启动两个线程一个是main方法另一个是GC
如果现在希望一个程序跑的慢一点,或者说暂缓执行,可以使用Thread类中提供的sleep()方
该方法需要的参数long类型的毫秒时间
范例:使用Sleep方法暂缓线程
在Thread类中里面提供了线程的终断的方法
通过以上方法可以让一个叫做正在休眠的线程终断休眠
以上方法可以判断一个线程是否已经被打断,已经被打断线程不能再次被打断
所谓线程的强制执行,指的是当一个线程满足条件之后,会一直占用资源直到这个线程执行完毕之后,其他线程在去访问资源
所谓线程的礼让就是在执行的时候当前不执行,先让别的线程执行.在Thread中提供了一个
线程的执行的时候是可以设置优先级的,理论上来说谁的优先级高谁就先执行,但是在线程中优先级也是一个叫做相对的概念,而不是绝对的。
通过以上代码,可以对线程设置优先级,但是发现在设置优先级之后线程的执行也不是按照优先级执行的,优先级只会对线程增加执行的概率而已
范例:取得主线程的优先级
在多线程中Thread描述的是一个个线程对象,而Runnable描述的是资源,当多个线程对象同时访问同一资源,操作不当的情况下会产生数据的错误
以上的问题为:多个对象同时访问一个资源的时候,由于多个对象在抢占资源,有可能多个对象同一时间对资源进行修改,这样就造成了数据的不同步
如果想要让线程不出现数据错误的现象则需要在操作的资源上加上同步锁,则这样之后每一个线程对象在操作的资源的时候后面线程对象会等到之前的线程对象操作完毕之后才会进行资源的操作
异步:多个线程对象可以同一时间对资源进行访问
同步:同一时间只能有一个线程在操作资源,剩下的线程只能等待上一个线程操作完毕之后在进行资源的操作
同步:由于每个线程只能单独进行资源的操作,所以效率不高
异步:异步处理由于多个线程可以同时进行资源的访问效率很高但是不安全
现在问题已经分析出来了。主要的原因是异步和同步的问题,如果想要解决以上的问题则需要在操作资源上进行同步锁的添加
在多线程中可以用两种方式实现同步锁:
关键字:synchronized这个单词必须能默写出来
通过以上的关键字就可以实现两种方式:
队列又分为顺序队列和循环队列
顺序队列存在假溢出的问题
由于顺序队列存在假溢出的问题,所以可以使用循环队列解决 特点:队头和队尾首尾相连
在循环队列中解决假溢出的问题:
少使用一个空间的情况下: