✅ 个人整理的对应知识点的面试题
👉 点击目录可跳转
🏆 信念: 种一棵树,最好的时间就是现在! 共勉!🤝🔌🔌通过总结、梳理,给自己充电!!!加油!
✅ 前言:我们都知道计算机的核心是CPU,它承担了所有的计算任务,而操作系统是计算机的管理者,它负责任务的调度,资源的分配和管理,统领整个计算机硬件;应用程序是具有某种功能的程序,而程序是运行于操作系统之上的。
1. 👉基本概念
1.1 程序
为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象。
1.2 进程与线程 ✅
进程:程序运行和资源分配的基本单位,进程在执行过程中拥有独立的内存单元,而线程进行划分的尺度一般要小很多,多个线程共享内存资源,减少了切换次数,这就导致了多线程的一些程序能够出现更高的并发性(效率更高)。一个程序都必须要有一个以上的进程,而相对于一个进程而言,也必须要要有一个以上的线程。
线程:线程是CPU调度和分派的基本单位,它是进程的一部分,只能由进程创建,是进程的一个实体,同一进程中的多个线程之间可以并发执行。
1.3 进程与线程的区别 ✅
- 区别
- 根本:进程是程序运行和资源分配的基本单元,而线程是处理器任务调度的和执行的基本单位。
- 关系:包含关系,线程是进程的一部分,可以把线程看作是轻量级的进程,一个进程内的线程是并发执行的。
- 内存分配:进程之间地址空间和资源独立;同一进程的线程共享本地的地址空间和资源。
- 开销:进程的创建和撤销,操作系统相应地要进行分配和回收资源,这远大于线程的创建和撤销时的开销。
1.4 并发和并行 ✅
- 并发
- 多个事件都处于同一个处理机上,同一个时间间隔内发生。
- 并行
- 多处理器上的程序才可实现并行处理,即不同实体上的多个事件同时发生。或者说,同时发生的多个并发事件;但并发不一定并行,并发事件之间不一定要同一时刻发生。
1.5 同步、异步、互斥 ✅
- 同步
- 同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。
- 异步
- 异步和同步是相对的,异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。
- 互斥
- 进程之间相互排斥的使用临界资源的现象。
2. 👉多线程
2.1 基本概念
多线程:多线程是程序设计的逻辑层概念,它是进程中并发运行的一段代码,多线程可以实现线程间的切换执行。是异步的一种实现方式,一种手段,它是最终目的。
2.2 创建线程的方式?✅
- 继承Thread类创建线程
- 实现 Runnable 接口创建线程
- 通过 Callable 和 Future 创建线程
- 通过线程池创建线程
2.2.1 继承Thread类创建线程
public class ThreadDemo extends Thread{
@Override
public void run() {
//run方法的线程体
for (int i = 0; i < 25; i++) {
System.out.println("正在运行"+i);
}
}
public static void main(String[] args) {
//主线程 main
//创建一个线程对象
ThreadDemo threadDemo = new ThreadDemo();
//调用strat()方法开启线程,交替执行的
//若调用run方法,则是按顺序执行
threadDemo.start();
// threadDemo.run();主线程
for (int i = 0; i < 100; i++) {
System.out.println("多线程案例"+i);
}
}
}
运行结果:
线程是同时执行的,每次执行的顺序不一定相同,由CPU安排调度的
小案例:
练习Thread,实现多线程同步下载图片,导入了一个common IO的jar包 这里面的图片链接可以自己更换
代码实现:
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//练习Thread,实现多线程同步下载图片 导入了一个common IO的jar包
public class ThreadDemo02 extends Thread {
private String url;
private String name;
//构造方法 初始化
public ThreadDemo02(String url,String name){
this.url = url;
this.name = name;
}
//run方法是线程的执行体 ,重写run()方法
@Override
public void run() {
//创建下载器对象
WebDownloader webDownloader = new WebDownloader();
//调用下载方法
webDownloader.downloader(url,name);
System.out.println("下载了图片,文件名为:"+name);
}
//主线程
public static void main(String[] args) {
//创建线程对象
ThreadDemo02 t1 = new ThreadDemo02("\thttps://img-blog.csdnimg.cn/img_convert/4a295f7dd5255538958201ce0e637d11.png","jori1.png");
ThreadDemo02 t2 = new ThreadDemo02("\thttps://img-blog.csdnimg.cn/img_convert/88c9e642358704ad7a568169861af2ce.png","jori2.png");
ThreadDemo02 t3 = new ThreadDemo02("\thttps://img-blog.csdnimg.cn/img_convert/20fb1225302c1c4070e929a6ab7f755e.png","jori3.png");
//线程是同时执行的,每次执行的顺序不一定相同,由CPU安排调度的
t1.start();
t3.start();
t2.start();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));//把url保存到文件
} catch (IOException e) {
e.printStackTrace();
System.out.println("iO异常,downloader方法出现问题!");
}
}
}
运行结果:
2.2.2 实现 Runnable 接口创建线程
//创建线程方式2 实现runnable接口
public class RunnableDemo implements Runnable{
// 重写run方法
@Override
public void run() {
for (int i = 0; i < 25; i++) {
System.out.println("正在运行中"+i);
}
}
//main主线程
public static void main(String[] args) {
//思路:执行线程先创建runnable实现类的对象,继续创建一个Thread对象,放入runnable接口实现类,再调用start方法
RunnableDemo runnableDemo = new RunnableDemo();//先创建runnable实现类的对象
Thread thread = new Thread(runnableDemo);//继续创建一个Thread对象,放入runnable接口实现类
thread.start();//再调用start方法
/*以上两行代码可以简写为:
new Thread(runnableDemo).start();
*/
for (int i = 0; i < 100; i++) {
System.out.println("多线程"+i);
}
}
}
练习Thread,实现多线程同步下载图片 这次采用实现Runnable接口
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/*练习Thread,实现多线程同步下载图片 这次采用实现Runnable接口,推荐用这种方式,因为采用Thread
的话,是单继承的,有局限性,而实现接口,可以实现多个接口*/
public class RunnableDemo02 implements Runnable {
private String url;
private String name;
//构造方法 初始化
public RunnableDemo02(String url,String name){
this.url = url;
this.name = name;
}
//run方法是线程的执行体 ,重写run()方法
@Override
public void run() {
//创建下载器对象
WebDownloader webDownloader = new WebDownloader();
//调用下载方法
webDownloader.downloader(url,name);
System.out.println("下载了图片,文件名为:"+name);
}
//main()主线程
public static void main(String[] args) {
//先创建runnable实现类的对象,构造方法初始化
RunnableDemo02 r1 = new RunnableDemo02("\thttps://img-blog.csdnimg.cn/img_convert/4a295f7dd5255538958201ce0e637d11.png","jori1.png");
RunnableDemo02 r2 = new RunnableDemo02("\thttps://img-blog.csdnimg.cn/img_convert/88c9e642358704ad7a568169861af2ce.png","jori2.png");
RunnableDemo02 r3 = new RunnableDemo02("\thttps://img-blog.csdnimg.cn/img_convert/20fb1225302c1c4070e929a6ab7f755e.png","jori3.png");
//线程是同时执行的,每次执行的顺序不一定相同,由CPU安排调度的
new Thread(r1).start();
new Thread(r2).start();
new Thread(r3).start();
}
//下载器
class WebDownloader {
//下载方法
public void downloader(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));//把url保存到文件
} catch (IOException e) {
e.printStackTrace();
System.out.println("iO异常,downloader方法出现问题!");
}
}
}
}
练习 2:龟兔赛跑
public class RaceDemo implements Runnable {
//胜利者只有一个,用static
private static String winner;
//重写run()
@Override
public void run() {
for (int i = 0; i < 101; i++) {
//当前线程是兔子的时候,每10步让他休息会,让乌龟线程先跑
if (Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
Boolean flag = gameOver(i);
if (flag){//为true则比赛结束了,退出程序
break;
}
System.out.println(Thread.currentThread().getName()+"-->>跑了"+i+"步");
}
}
//判断是否完成比赛
private boolean gameOver(int steps) {
//判断胜利者是否存在
if (winner != null) {//说明存在胜利者了
return true;
}
{
if (steps >= 100) {
winner = Thread.currentThread().getName();//获取当前线程的名字
System.out.println("winner is " + winner);
return true;
}
}
return false;
}
//main()主线程
public static void main(String[] args) {
RaceDemo raceDemo = new RaceDemo();
new Thread(raceDemo,"兔子").start();
new Thread(raceDemo,"乌龟").start();
}
}
2.2.3 通过 Callable 和 Future 创建线程
实现Callable接口 Callable实现图片下载案例
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
//扩充 线程创建方式三 实现Callable接口 Callable实现图片下载案例
/*callable的好处
* 1 可以定义返回值
* 2 可以主动抛出异常*/
public class CallableDemo implements Callable<Boolean> {
private String url;//网络图片地址
private String name;//保存的文件名
//构造方法 初始化
public CallableDemo(String url,String name){
this.url = url;
this.name = name;
}
//run方法是线程的执行体 ,重写run()方法
@Override
public Boolean call() {
//创建下载器对象
WebDownloader webDownloader = new WebDownloader();
//调用下载方法
webDownloader.downloader(url,name);
System.out.println("下载了图片,文件名为:"+name);
return true;
}
//主线程
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程对象
CallableDemo t1 = new CallableDemo("\thttps://img-blog.csdnimg.cn/img_convert/4a295f7dd5255538958201ce0e637d11.png","jori1.png");
CallableDemo t2 = new CallableDemo("\thttps://img-blog.csdnimg.cn/img_convert/88c9e642358704ad7a568169861af2ce.png","jori2.png");
CallableDemo t3 = new CallableDemo("\thttps://img-blog.csdnimg.cn/img_convert/20fb1225302c1c4070e929a6ab7f755e.png","jori3.png");
//线程是同时执行的,每次执行的顺序不一定相同,由CPU安排调度的
/*开启线程步骤:
* 1 创建执行服务 通过服务提交执行
* 2 提交执行
* 3 获取结果
* 4 关闭服务*/
ExecutorService ser = Executors.newFixedThreadPool(3);//创建执行服务
Future<Boolean> r1 = ser.submit(t1);//提交执行
Future<Boolean> r2 = ser.submit(t2);
Future<Boolean> r3 = ser.submit(t3);
//获取结果 这里主动抛出异常
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
//打印一下返回值
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
ser.shutdown();//关闭服务
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));//把url保存到文件
} catch (IOException e) {
e.printStackTrace();
System.out.println("iO异常,downloader方法出现问题!");
}
}
}
}
2.2.4 通过线程池创建线程
//线程池测试
// 执行部分:可以用 execute 或者submit ,execute 放入的时Ruannable接口的实现类,没有返回值 submit放入的是Callable的实现类 有返回值
public class PoorDemo {
public static void main(String[] args) {
// 1.创建服务,创建线程池 newFixedThreadPool(10);//池子大小
ExecutorService service = Executors.newFixedThreadPool(10);//池子大小
// 2、执行Runnalbe接口的实现类 放入到excute
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
// 3、关闭服务
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
2.3 静态代理模式✅
静态代理模式是代理模式的其中一种,而代理模式又是23种设计模式之一
2.3.1 什么是静态代理模式?
对其他对象提供一种代理以控制对这个对象的访问。举个例子,如A对象有若干个方法,这时A对象对B对象进行委托授权,B对象便成了A对象的代理方,因此B对象便可对A对象进行访问并调用A对象的方法,相当于A对象调用自己的方法。现实生活中就行火车票代售点一样。
简单的说:代理模式,字面上的意思就是代理某个人去做某件事。比如代办证件,可以找代办公司帮忙代理办证。
2.3.2 静态代理模式案例
- 将静态代理模式的三部分分别理解程:接口、客户端、委托类,并通过以下案例来演示
案例:婚庆公司代理YOU去结婚
- 接口
//定义一个结婚的接口
interface Marry{
void GetMarry();
}
- 客户端
//真实角色 实现接口
class You implements Marry{
//真实角色专注于做自己的事情
@Override
public void GetMarry() {
System.out.println("you结婚了!很开心!");
}
}
- 委托类
//代理角色 婚庆公司 实现接口
class WeddingCommpany implements Marry{
private Marry target;//对象类型的target,(new You() 匿名对象的传入)
//构造方法
public WeddingCommpany(Marry target) {
this.target = target;
}
//重写方法 该方法封装了真实对象的request方法
@Override
public void GetMarry() {
before();//添加了真实代理没有的方法
target.GetMarry();//调用的是 代理类
after();//添加了真实代理没有的方法
}
private void before() {
System.out.println("结婚之前,筹备婚礼!");
}
private void after() {
System.out.println("结婚之后,交付尾款!");
}
}
- 主函数
public class StaticProxyDemo {
public static void main(String[] args) {
WeddingCommpany weddingCommpany = new WeddingCommpany(new You());//匿名对象 传入到代理中
weddingCommpany.GetMarry();//调用的是婚庆公司,但是结婚的是you
/* 将上面两行代码简化成一行代码:new WeddingCommpany(new You()).GetMarry()*/
}
- 类比一个类(假设是RunnableDemo)继承Runnable接口并用Thread类代理
//实现多线程,实现Runnable接口 外面的代理给里面的真实对象做事,代理和真实对象都实现了同一个接口 如: Thread 和new RunnableDemo()都实现了Runnable接口 /* new Thread(new Runnable() { @Override public void run() { System.out.println("i love you!"); }*/ //lambda表达式 jdk8 新特性 new Thread(()->System.out.println("i love you")).start() ;
效果:
静态代理模式总结:
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实对象
好处: - 代理对象可以做很多真实对象做不到的事情
- 真实对象专注做自己的事情
缺点:静态代理对于代理的角色是固定的,如dao层有20个dao类,如果要对方法的访问权限进行代理,此时需要创建20个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。(之后再总结出来)