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

相关推荐
qq_334903152 小时前
C++中的装饰器模式高级应用
开发语言·c++·算法
灰色小旋风2 小时前
力扣14 最长公共前缀(C++)
java·数据结构·算法
枫叶丹42 小时前
【HarmonyOS 6.0】Network Kit 深度解析:TLS 认证全面支持国密证书
开发语言·网络安全·华为·harmonyos
2401_851272992 小时前
编译器内建函数使用
开发语言·c++·算法
魑-魅-魍-魉2 小时前
Maven + Nexus 连接被拒绝问题速查手册
java·maven
caimouse2 小时前
Node.js的http服务
开发语言
yuhaiqiang2 小时前
AI 正在偷走大家的独立思考能力……
前端·后端·面试
不会写DN2 小时前
[特殊字符] JS Date 对象8大使用场景
开发语言·前端·javascript