1.进程和线程的关系?
进程:运行后的程序,是操作系统分配系统资源(内存空间、CPU)的最小单位。
线程:每个进程由一个或多个线程组成,线程是CPU进行分配和调度的最小单位(分配时间片)。
2.创建线程的几种方式?
1.继承Thread类: 定义类继承Thread类,重写run方法,创建线程对象,调用start方法。
2.实现Runnable接口:定义类实现Runnable接口, 实现run方法,创建Thread对象,传入Runnable对象,调用start。
3.实现Callable接口:实现Callable接口的call方法,创建FutureTask对象传入Callable实现对象, 创建Thread线程传入FutureTask对象,启动线程, 通过FutureTask的get方法获得返回值。
3.继承Thread类和实现Runnable两种方式的区别?
1.Java是单继承的,继承Thread类就不能继承其它类,实现接口没有此限制。
2.继承Thread不强制要求重写run,实现Runnable强制要求。
3.Runnable可以使用Lambda表达式,语法简介。
4.启动线程使用start还是run?
使用start,因为调用run是在主线程中同步执行的,调用start后才会启动新线程去执行。
5.多线程的执行是什么顺序?
上下文切换
多线程的执行是抢占式的,线程会去抢占CPU,抢到后执行自己的指令,执行过程中CPU可能被其它线程抢占,其它线程执行
上下文切换回原来线程时,如何执行从哪里开始执行?
每个线程有自己的程序计数器,保存当前线程执行的行数,切换回来后继续执行下面的行代码
6.sleep和wait区别?
1.调用对象不同: wait是锁对象调用,sleep是当前线程调用
2.唤醒机制不同: 线程进入wait后,要通过锁对象notify/notifyAll唤醒,sleep当时间结束自动唤醒
3.锁释放不同:线程进入wait后,会自动释放锁,线程sleep不会释放锁
7.线程的生命周期?
-
新建(new线程的时候)
-
就绪/准备(调用start方法的时候)
-
运行(抢占cpu的时候)
-
阻塞(调用一些方法时会造成阻塞)
-
死亡(run方法执行完)
8.什么是线程同步问题,出现的原因和解决方法?
多个线程同时访问一个资源(变量、代码块、数据等),可能出现线程同步问题。
出现的原因:多个线程的执行是抢占式的,一个线程在执行一系列程序指令中途时,就被其它线程抢占,可能导致数据状态出现问题。
解决方式:锁机制
9.三种锁机制的区别?
1.同步方法和同步代码块的区别?
1)语法不同,一个写在方法上,一个写在方法内部。
2)锁粒度不同,同步方法作用于整个方法,同步代码块作用于一段代码。
3)性能不同,同步方法低于同步块。
4) 锁对象不同,同步方法是固定的,静态就是类.class,非静态的就是this。
同步代码块可以指定锁对象。
2.synchronized和同步锁的区别?
上锁:synchronized是自动上锁和解锁,同步锁是手动完成的。
性能:同步锁的性能高于synchronized。
使用:synchronized使用简单,功能单一,同步锁提供更多方法,使用灵活。
对比三种锁机制:
粒度: 同步方法 > 同步块/同步锁
性能: 同步锁 > 同步块 > 同步方法
方便: 同步方法 > 同步块 > 同步锁
10.synchronized的原理?
通过监视器(monitor)完成
当对方法或一段代码上锁后,会启动监视器对这段代码监控,监视器中有计数器,当计数器为0时,允许线程进入,线程进入后,计数器加1,其它线程访问时,计数器不为0,不允许线程进入,线程执行完代码块后,计数器减1为0 ,监视器允许其它线程进入。
11.手写双检锁单例模式?
12.手写线程死锁的案例?
13.volatile关键字的作用,和synchronized的区别是?
volatile的作用:
变量前加上volatile,保证可见性,线程在修改此变量时,是在主内存中直接进行修改,其它线程马上可以看到,不存在数据不一致的情况。volatile可以禁止指令重排。
synchronized和volatile的区别?
修饰的对象:synchronized修改代码块或方法,volatile只能修饰变量。
保证的特性:synchronized保证原子性、可见性;volatile不能保证原子性,保证可见性和有序性。
性能:volatile是轻量级的线程同步方式,性能更高。
14.乐观锁和悲观锁的区别?
悲观锁:比较悲观,认为线程同步问题会经常出现,倾向于给资源上锁