目录
==和equals
最近复习Java基础知识突然发现对euqals和==分辨不清楚了,回头查了下资料发现写的都不怎么好不能一眼看到结果,所以我把结果直接放到下面。
在==情况下:
如果是基本类型:内容相同则为true;
如果是引用类型:则在内存中地址相同则为true,也就是说引用类型必须相同。
而equals(): //底层实现方法也是==
在不重写equals方法情况下,如果是引用类型,和==效果相同,比较的也是地址。
但是String类重写了这个方法,比较的则是内容。
接口类和抽象类有什么区别?
- 他们都是上层的抽象层,都包含抽象的方法用于描述具体的功能但不实现。 他们都不能被实例化。
- 抽象类中可以有非抽象的方法;而接口只能有抽象方法。
- 一个类可以实现多个接口但只能有继承一个父类。(Java中实现多继承的原理也在于这里)
- 抽象类的关注的是类的本质特征,接口关注的是类的行为操作。
创建线程有几种方式
四种
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 使用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
线程安全
解决线程安全问题:线程同步
如下三种方法:
- 同步代码块
- 同步方法
- 锁机制
第一种:同步代码块
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. 加载