【Java八股 |JUC并发编程类】线程

一、介绍一个Java的内存模型(JMM)

JMM是专门解决多线程并发问题下的一套规则。主要解决的问题有原子性,可见性和有序性。

  • **原子性:**操作不可分割,要么同时成功,要么同时失败。不能有其他线程插入。通过加锁和CAS(配合volatile)实现
  • **可见性:**线程A修改了共享变量的值,线程B也能立马看到。通过volatile关键字和加锁实现。
  • 有序性: 编译器或者CPU为了提速会在不影响单线程结果的前提下修改指令顺序,也就是说代码执行顺序和你写的不一样!在单线程情况下不会出错,但在多线程情况下数据会发生错误。有序性就是防止指令重新排序导致的逻辑错误。通过volatile关键字和加锁实现。

JMM把内存抽象为以下两类:

  • **主内存(Main Memory) :**所有线程共享,存放实例对象、静态变量、数组等共享数据。
  • 工作内存(Working Memory): 每个线程私有,线程操作变量时,会先把需要用到的数据从主内存数据拷贝到自己的工作内存,操作完再写回主内存。

二、Java多线程是什么?需要注意什么?

Java多线程是指在一个程序中同时运行多个线程,所有线程共享程序的内存空间,但每个线程都有各自的栈和程序计数器。

需要注意:
**1.线程安全问题:**多个线程同时对一个共享变量进行操作是可能会出现数据错误.。主要是原子性、可见性和有序性。
**2.线程的销毁与创建成本:**线程的不断销毁和创建会浪费系统资源,到时性能降低。推荐使用线程池来管理线程。

除此之外还有例如死锁,线程间通讯,停止线程等就不一一罗列。


三、Java里面的线程和操作系统的线程一样吗?

本质上是一样的。


四、线程的创建方式有哪些?

1.继承Thread类

继承Thread,重写run方法,创建对象,调用start()方法;

Java是单继承的,继承了Thread就无法继承其他类

java 复制代码
// 自定义线程类,继承 Thread
class MyThread extends Thread {
    // 重写 run 方法,定义线程执行的任务
    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建线程实例
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        // 启动线程
        thread1.start();
        thread2.start();
    }
}
 

2.实现Runnable接口

实现Runnable接口,重写run方法,创建Runnable实例,传入Thread构造,调用start方法;

避免了Java的单继承机制。

java 复制代码
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程正在执行,实现方式:实现Runnable接口");
    }

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}
 

3.实现Callable接口

搭配FutureTask使用。重写call方法,创建Callble实例,将Callable包装为FutureTask,传入Thread构造,调用start方法。

避免了Java的单继承机制。

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ExecutionException;

public class CallableWithFutureTaskExample {

    // 定义一个实现Callable接口的任务
    static class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            // 模拟耗时操作
            Thread.sleep(1000);
            return "Callable任务执行完成";
        }
    }

    public static void main(String[] args) {
        // 创建Callable实例
        MyCallable callable = new MyCallable();

        // 将Callable包装为FutureTask
        FutureTask<String> futureTask = new FutureTask<>(callable);

        // 启动线程执行任务
        Thread thread = new Thread(futureTask);
        thread.start();

        try {
            // 获取任务执行结果(阻塞直到任务完成)
            String result = futureTask.get();
            System.out.println("任务结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}
 

4.使用线程池(实际开发最常用)

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建固定大小的线程池(实际开发推荐使用自定义的ThreadPoolExecutor)
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 提交10个任务到线程池
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务耗时
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 优雅关闭线程池
        executor.shutdown();
    }
}
 

五、如何停止一个线程?

1. 最佳方案:自定义 volatile 标志位

class MyThread extends Thread {
// 必须 volatile 保证可见性
private volatile boolean stop = false;

@Override
public void run() {
while (!stop) {
// 正常业务逻辑
}
System.out.println("线程安全退出");
}

// 对外提供停止方法
public void stopThread() {
stop = true;
}
}

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

t.stopThread(); // 温和停止

2. 官方推荐:使用 interrupt() 中断机制

Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
// 执行业务
Thread.sleep(1000);
} catch (InterruptedException e) {
// 收到中断信号,退出循环
break;
}
}
});
t.start();

t.interrupt(); // 发送中断信号

3.线程池中停止

shutdown()

shutdownNow()(底层调用了interrupt)

4.强制停止(已废弃,非常不推荐)

相关推荐
ZK_H1 天前
嵌入式c语言——关键字其6
c语言·开发语言·计算机网络·面试·职场和发展
A.A呐1 天前
【C++第二十九章】IO流
开发语言·c++
椰猫子1 天前
Java:异常(exception)
java·开发语言
lifewange1 天前
pytest-类中测试方法、多文件批量执行
开发语言·python·pytest
GreenTea1 天前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
cmpxr_1 天前
【C】原码和补码以及环形坐标取模算法
c语言·开发语言·算法
2401_827499991 天前
python项目实战09-AI智能伴侣(ai_partner_5-6)
开发语言·python
PD我是你的真爱粉1 天前
MCP 协议详解:从架构、工作流到 Python 技术栈落地
开发语言·python·架构
win x1 天前
Redis 使用~如何在Java中连接使用redis
java·数据库·redis
星晨雪海1 天前
基于 @Resource 的支付 Service 多实现类完整示例
java·开发语言