Java基础面试题(07)—Java(线程)
·
前言
学习项目的过程中,我觉得自己有点太急功近利了一直跟着视频敲没有自己的思考(主要是最近在牛客读到了一位大佬👍👍👍,程序员牛肉的文章),🙌学技术不是一味的复制粘贴,特别是做项目,要边学边思考,一个功能的实现,我学会了什么技术,还有没有更好的可以替代它。
之前学的基础知识其实也没有学完,像集合,线程… 都还不知道是啥就开始学JavaWeb做项目了,在项目中使用队列存储我都一脸懵,在这里以问题的形式写一个学习笔记🤔,不仅仅是复习,也为以后的面试做准备,还有还有我的刷题网站是面试鸭呦🦆🦆🦆
一、什么是线程?
- 进程 (Process): 一个正在运行的程序就是一个进程。进程是操作系统进行资源分配和调度的基本单位。每个进程都有自己独立的内存空间(堆、栈、代码段、数据段等)。
- 线程 (Thread): 线程是进程中的一个执行单元,是 CPU 调度和执行的基本单位。一个进程可以包含多个线程,这些线程共享该进程的内存资源(如堆内存、方法区),但每个线程拥有自己独立的栈空间(用于存储局部变量和方法调用)。
🙌🙌🙌可以这样理解:一个进程就像一个工厂,而线程就是工厂里的工人。工厂(进程)拥有所有的机器和原材料(内存资源),工人们(线程)共享这些资源,但每个工人有自己的工作台(栈空间)和工作任务(执行流)
二、Java 中创建线程的两种主要方式
在 Java 中,创建线程主要有三种方法:
方法一:继承 Thread 类
- 创建一个类,继承 java.lang.Thread 类。
- 重写 Thread 类的 run() 方法。这个方法中包含了线程要执行的代码。
- 创建该类的实例。
- 调用实例的 start() 方法来启动线程。
class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的任务
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(1000); // 模拟耗时操作,让线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 启动线程
thread1.start(); // 调用start(),JVM会自动调用run()方法
thread2.start();
}
}
💡注意: 直接调用run方法会当成普通方法执行,相当于还是单线程,只有调用start方法才是一个新的线程,不要把主线程任务放在启动子线程之前。
方法二:实现 Runnable 接口
- 创建一个类,实现 java.lang.Runnable 接口。
- 实现 Runnable 接口的 run() 方法。
- 创建该类的实例。
- 将该实例作为参数传递给 Thread 类的构造函数,创建 Thread 对象。
- 调用 Thread 对象的 start() 方法来启动线程。
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable task = new MyRunnable();
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task); // 多个线程可以共享同一个Runnable实例
thread1.start();
thread2.start();
}
}
🧩优缺点:
- 优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
- 缺点:需要多一个Runnale对象。。
匿名内部类写法:
- 可以创建Runnable的匿名内部类对象
- 在交给Thread线程对象。
- 再调用线程对象的start()启动线程。
//源代码
public static void main(String[] args) {
Runnable r = new MyRunnable();
Thread t1 = new Thread(r);
t1.start();
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++ ) {
System.out.println("子线程:" + i);
}
}
}
//匿名内部类写法:
public static void main(String[] args) {
new Thread(new Runnable () {
@Override
public void run() {
for (int i = 0; i < 5; i++ ) {
System.out.println("子线程:" + i);
}
}) .start();
}
//Lambda表达式
public static void main(String[] args) {
new Thread(()-> {
@Override
public void run() {
for (int i = 0; i < 5; i++ ) {
System.out.println("子线程:" + i);
}
}) .start();
}
方法三:实现 Callable 接口
前两种线程创建方式都存在的一个问题
假如线程执行完毕后一些数据需要返回,他们重写的run方法均不能直接返回结果。
- 创建任务对象
- 定义一个类实现Callable接口, 重写call方法,封装要做的事情,和要返回的数据。
- 把Callable类型的对象封装成FutureTask。
- 把线程任务对象交给Thread对象
- 调用Thread对象的start方法启动线程
- 线程执行完毕后,通过FutureTask对象的get方法去获取线程任务执行的结果。
public static void main(String[] args) {
Callable<String> c1 = new MyCallable(100);
FutureTask<String> f1 = new FutureTask<>(c1);
Thread t1 = new Thread(f1);
t1.start();
}
//定义一个类实现Callable接口, 重写call方法
class MyCallable implements Callable <String> {
private int n;
public MyCallable (int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 1; i < n; i++ ) {
sum += i;
}
return "子线程计算结果是" + sum;
}
}
四、线程常用方法
- start(): 启动线程,JVM 会调用该线程的 run() 方法。注意:直接调用 run() 方法不会启动新线程,只是在当前线程中执行方法。
- run(): 包含线程要执行的代码。通常由 start() 方法间接调用。
- sleep(long millis): 静态方法,使当前线程休眠指定的毫秒数。休眠期间线程进入 TIMED_WAITING 状态,不会释放锁。
- join(): 当前线程等待调用 join() 的线程执行完毕后再继续执行。可以带超时时间 join(long millis)。
- interrupt(): 中断线程。如果线程处于 sleep(), wait(), * join() 等阻塞状态,会抛出 InterruptedException;如果线程在运行,则会设置线程的中断标志位。
- isInterrupted(): 检查线程的中断状态,不清除中断标志。
Thread.interrupted(): 静态方法,检查当前线程的中断状态,并清除中断标志。 - currentThread(): 静态方法,返回当前正在执行的线程对象。
- getName(), setName(String name): 获取/设置线程名称。
class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的任务
for (int i = 0; i < 5; i++) {
System.out.println("子线程输出:" + i);
try {
Thread.sleep(1000); // 模拟耗时操作,让线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 启动线程
thread1.start(); // 调用start(),JVM会自动调用run()方法
System.out.println(thread1.getName());
thread2.start();
System.out.println(thread2.getName());
Thread m = Thread.currentThread();//主线程
m.setName("主线程");
System.out.println(m.getName());
}
}
小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)
…。。。。。。。。。。。…
…。。。。。。。。。。。…
更多推荐
所有评论(0)