【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.强制停止(已废弃,非常不推荐)

相关推荐
MATLAB代码顾问6 小时前
5大智能算法优化标准测试函数对比(Python实现)
开发语言·python
wuminyu8 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
万粉变现经纪人8 小时前
如何解决 pip install llama-cpp-python 报错 未安装 CMake/Ninja 或 CPU 不支持 AVX 问题
开发语言·python·开源·aigc·pip·ai写作·llama
小码哥_常8 小时前
Spring Boot:别再重复造轮子,这些内置功能香麻了
后端
清风明月一壶酒8 小时前
OpenClaw自动处理Word文档全流程
开发语言·c#·word
其实防守也摸鱼8 小时前
CTF密码学综合教学指南--第五章
开发语言·网络·笔记·python·安全·网络安全·密码学
皮皮林5518 小时前
OpenFeign 首次调用卡 3 秒?八年老开发扒透 5 个坑,实战优化到 100ms!
后端
callJJ9 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
小郑加油9 小时前
python学习Day12:pandas安装与实际运用
开发语言·python·学习
AC赳赳老秦9 小时前
投标合规提效:用 OpenClaw 实现标书 / 合同自动审核、关键词校验、格式优化,降低废标风险
开发语言·前端·python·eclipse·emacs·deepseek·openclaw