Java面试基础知识

 

目录

==和equals

接口类和抽象类有什么区别?

 创建线程有几种方式



==和equals

最近复习Java基础知识突然发现对euqals和==分辨不清楚了,回头查了下资料发现写的都不怎么好不能一眼看到结果,所以我把结果直接放到下面。

在==情况下:

如果是基本类型:内容相同则为true;

如果是引用类型:则在内存中地址相同则为true,也就是说引用类型必须相同。

而equals():   //底层实现方法也是==

在不重写equals方法情况下,如果是引用类型,和==效果相同,比较的也是地址。

但是String类重写了这个方法,比较的则是内容。


接口类和抽象类有什么区别?

  1. 他们都是上层的抽象层,都包含抽象的方法用于描述具体的功能但不实现。  他们都不能被实例化。
  2. 抽象类中可以有非抽象的方法;而接口只能有抽象方法。
  3. 一个类可以实现多个接口但只能有继承一个父类。(Java中实现多继承的原理也在于这里)
  4. 抽象的关注的是类的本质特征,接口关注的是类的行为操作。

 创建线程有几种方式

 四种

  1. 继承Thread类     
  2. 实现Runnable接口
  3. 实现Callable接口
  4. 使用Executors创建线程池

方法1>继承Thread类:MyThread继承Thread

MyThread myThread = new MyThread(); 	
        myThread.start();

方法2>实现Runnable接口:定义Runnable接口实现类MyRunnable,并重写run()方法,创建MyRunnable实例myRunnable,以myRunnable作为目标创建Thead对象,该Thread对象才是真正的线程对象,调用线程对象的start()方法

MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();

 

3>实现Callable接口:创建实现Callable接口的类myCallable,重写call方法,以myCallable为参数创建FutureTask对象,将FutureTask作为参数创建Thread对象,调用线程对象的start()方法。

        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
        Thread thread = new Thread(futureTask);
        thread.start();

4>使用 Executors 工具类创建线程池

问题:说一下 runnable 和 callable 有什么区别?

Runnable 接口 run 方法无返回值;Callable 接口 call 方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;Callable 接口 call 方法允许抛出异常,可以获取异常信息。

明天继续~ 

2020.4.13   00:57


2020.4.14   8:00

线程安全

解决线程安全问题:线程同步

如下三种方法:

  1. 同步代码块
  2. 同步方法
  3. 锁机制

 第一种:同步代码块

synchronized(锁对象) {
可能会出现线程安全问题的代码(访问共享数据的代码)
}
//注意:
//(1)、通过代码块的锁对象,可以是任意对象
//(2)、必须保证多个线程使用的锁对象必须是同一个
//(3)、锁对象的作用是把同步代码快锁住,只允许一个线程在同步代码块执行

原理:使用了一个锁对象,叫同步锁,对象锁,也叫同步监视器,当开启多个线程的时候,多个线程就开始抢夺CPU的执行权,比如现在t0线程首先的到执行,就会开始执行run方法,遇到同步代码快,首先检查是否有锁对象,发现有,则获取该锁对象,执行同步代码块中的代码。之后当CUP切换线程时,比如t1得到执行,也开始执行run方法,但是遇到同步代码块检查是否有锁对象时发现没有锁对象,t1便被阻塞,等待t0执行完毕同步代码块,释放锁对象,t1才可以获取从而进入同步代码块执行。同步中的线程,没有执行完毕是不会释放锁的,这样便实现了线程对临界区的互斥访问,保证了共享数据安全。

缺点:频繁的获取释放锁对象,降低程序效率。

第二种:同步方法

修饰符 synchronized 返回值类型 方法名称(参数列表) {
  方法体...
}
//
//1、把访问了共享数据的代码抽取出来,放到一个方法中
//2、在该方法上添加 synchronized 修饰符

同步方法的也是一样锁住同步的代码,但是锁对象的是Runable实现类对象,也就是this,谁调用方法,就是谁。

说到同步方法,就不得不说一下静态同步方法,顾名思义,就是在同步方法上加上static,静态的同步方法,添加一个静态static修饰符,此时锁对象就不是this了,静态同步方法的锁对象是本类的class属性,class文件对象(反射)。

第三种:锁机制

inport java.util.concurrent.locks.ReentrantLock;
public class RunableDemo implenents Runnable{
public static int a = 100://线程共享数据

ReentrantLock reentrantLock = new ReentrantLock():
@override
public void run() {
// 2.在可能产生线程安全问题的化码前该对象调用lock方法获取
reentrantLock.lock():
while (a>0){
System.out.println(“线程"+Thread.currentThread().getName()+"执行到"+ a);
a--;
// 3.在可能产生线程安全问题的代码后该对会调用unlock方法获取锁
reentrantLock.unlock():
}

总结:

第一种:

synchronized 同步代码块:可以是任意的对象必须保证多个线程使用的锁对象是同一个。

第二种:

synchronized 同步方法: 锁对象是this,谁调用锁对象就是谁

synchronized 静态同步方法: 锁对象是其class对象,该对象可以用this.getClass()方法获取,也可以使用当前类名.class 表示。【了解即可】

第三种:

Look锁方法:该方法提供的方法远远多于synchronized方式,主要在Runable实现类的成员变量创建一个ReentrantLock对象,并使用该对象调用lock方法获取锁以及unlock方法释放锁!

线程常用的方法

1、Thread类

Thread():用于构造一个新的Thread。

Thread(Runnable target):用于构造一个新的Thread,该线程使用了指定target的run方法。

Thread(ThreadGroup group,Runnable target):用于在指定的线程组中构造一个新的Thread,该线程使用了指定target的run方法。

currentThread():获得当前运行线程的对象引用。

interrupt():将当前线程置为中断状态。

sleep(long millis):使当前运行的线程进入睡眠状态,睡眠时间至少为指定毫秒数。

join():等待这个线程结束,即在一个线程中调用other.join(),将等待other线程结束后才继续本线程。

yield():当前执行的线程让出CPU的使用权,从运行状态进入就绪状态,让其他就绪线程执行。

2、Object类

wait():让当前线程进入等待阻塞状态,直到其他线程调用了此对象的notify()或notifyAll()方法后,当前线程才被唤醒进入就绪状态。

notify():唤醒在此对象监控器(锁对象)上等待的单个线程。

notifyAll():唤醒在此对象监控器(锁对象)上等待的所有线程。

注意:wait()notify()notifyAll()都依赖于同步锁,而同步锁是对象持有的,且每个对象只有一个,所以这些方法定义在Object类中,而不是Thread类中。

3、yield()、sleep()、wait()比较

wait():让线程从运行状态进入等待阻塞状态,并且会释放它所持有的同步锁。

yield():让线程从运行状态进入就绪状态,不会释放它锁持有的同步锁。

sleep():让线程从运行状态进入阻塞状态,不会释放它锁持有的同步锁。

线程池(后续补充)

Java类加载过程?

java类加载需要经历⼀下7个过程:

1. 加载

加载是类加载的第⼀个过程,在这个阶段,将完成⼀下三件事情:
    通过⼀个类的全限定名获取该类的⼆进制流。
    将该⼆进制流中的静态存储结构转化为⽅法去运⾏时数据结构。
    在内存中⽣成该类的 Class 对象,作为该类的数据访问⼊⼝。
2. 验证
验证的⽬的是为了确保 Class⽂件的字节流中的信息不会危害到虚拟机 . 在该阶段主要完成 以下四钟验证:
       ⽂件格式验证:验证字节流是否符合 Class ⽂件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被⽀持的类型.
       元数据验证 : 对字节码描述的信息进⾏语义分析,如这个类是否有⽗类,是否集成了 不被继承的类等。
       字节码验证:是整个验证过程中最复杂的⼀个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对⽅法体的验证。如:⽅法中的类型转换是否正确,跳转指令是否正确等。
       符号引⽤验证:这个动作在后⾯的解析过程中发⽣,主要是为了确保解析动作能正确执⾏。
3. 准备
准备阶段是为 类的静态变量分配内存并将其初始化为默认值 ,这些内存都将在⽅法区中进
⾏分配。 准备阶段不分配类中的实例变量的内存 ,实例变量将会在对象实例化时随着对象
⼀起分配在 Java 堆中。
public static int value=123;// 在准备阶段 value 初始值为 0 。在初始化阶段才会变为 123
4. 解析
该阶段主要完成符号引⽤到直接引⽤的转换动作。解析动作并不⼀定在初始化动作完成之前,
也有可能在初始化之后。
5. 初始化
初始化时类加载的最后⼀步,前⾯的类加载过程,除了在加载阶段⽤户应⽤程序可以通过⾃定
义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执⾏
类中定义的 Java 程序代码。
6. 使⽤
7. 卸载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KISSING_MONSTER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值