【JUC编程】一、线程的基础概念

一、线程的基础概念

1.1 进程与线程

进程

进程是操作系统分配资源的基本单位。每个运行中的程序都可以视为一个进程,操作系统会为它分配内存和其他资源。例如,我们启动钉钉、浏览器等程序时,它们就是在操作系统中以进程的形式存在。

线程

线程是进程中的执行单位,是CPU调度的基本单位。一个进程至少有一个线程,而这个线程负责执行进程的具体任务。线程是CPU调度的核心,每个线程都会执行进程中的某一部分代码。

举个例子:

  • 想象一座100平米的房子,这个房子就是进程。
  • 房子里的每个人就是一个线程,房子里的人可以同时做不同的事情,比如吃饭、看书、休息等。
进程与线程的区别
特性 进程 线程
资源分配 操作系统为进程分配资源 线程共享进程的资源
内存空间 独立的内存空间 共享进程的内存空间
调度 操作系统调度进程 CPU调度线程
创建开销 创建和销毁的开销较大 线程创建和销毁的开销较小
通信 进程间通信复杂,需要借助IPC机制 线程间通信简单,通过共享内存等方式

1.2 多线程

什么是多线程?

多线程是指在同一个进程中同时运行多个线程。通过多线程,可以让程序在进行I/O操作时不浪费CPU时间,提升系统性能。例如,Tomcat服务器可以同时处理多个客户端请求,而不是顺序排队。

多线程的优点
  • 提高CPU利用率:避免了CPU空闲,提升了系统效率。
  • 提升用户体验:在进行IO操作时,可以让其他任务继续执行,不会阻塞主流程。
多线程的局限
  • 线程切换开销:线程数量过多时,CPU切换线程的开销变大,导致性能下降。
  • 任务拆分困难:某些任务由于其复杂性,不容易拆分成多个子任务进行并行处理。
  • 线程安全问题:多个线程操作同一资源时,可能会引发数据不一致的安全问题,甚至造成死锁。

1.3 串行、并行与并发

  • 串行:任务按顺序执行,一个任务完成后才能执行下一个任务。
  • 并行:多个任务同时执行,通常在多核CPU中可以实现。
  • 并发:多个任务看似同时执行,但实际上是CPU在短时间内快速切换任务,单核CPU通过并发模拟并行。

1.4 同步与异步、阻塞与非阻塞

同步与异步
  • 同步:调用者需要等待操作完成后才会得到结果。
  • 异步:调用者发出请求后,不需要等待结果,可以继续执行其他操作。
阻塞与非阻塞
  • 阻塞:调用者发出请求后,需要一直等待结果,不做其他事情。
  • 非阻塞:调用者发出请求后,不需要等待结果,可以继续执行其他任务。

最佳方案 :在实际开发中,异步非阻塞是提升效率的最佳方式,尤其是在处理并发任务时。


二、线程的创建与使用

2.1 线程的创建

继承Thread

通过继承Thread类并重写run方法来创建线程。调用start()方法启动线程。

java 复制代码
public class MyTest {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running...");
    }
}
实现Runnable接口

实现Runnable接口并重写run方法,可以避免Java中类的单继承限制。通过创建Thread对象来启动线程。

java 复制代码
public class MyTest {
    public static void main(String[] args) {
        Runnable task = () -> System.out.println("Runnable is running...");
        Thread t1 = new Thread(task);
        t1.start();
    }
}
使用CallableFuture

Callable接口允许线程执行任务并返回结果,结合Future可以获取线程执行结果。

java 复制代码
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> task = () -> 10 + 20;
        FutureTask<Integer> future = new FutureTask<>(task);
        Thread t1 = new Thread(future);
        t1.start();
        System.out.println("Result: " + future.get());  // 等待线程执行结果
    }
}
基于线程池创建线程

线程池是Java中管理线程的一种方式,可以通过ExecutorService创建线程池,避免频繁创建销毁线程的开销。

java 复制代码
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("Thread from pool is running..."));
executor.shutdown();

2.2 线程的状态

线程的状态有以下几种:

  • NEW :线程被创建,但尚未调用start()方法。
  • RUNNABLE:线程处于可运行状态,等待CPU调度。
  • BLOCKED:线程因竞争资源(如锁)被阻塞。
  • WAITING :线程进入等待状态,需要外部操作(如notify)唤醒。
  • TIMED_WAITING:线程在限定时间内等待。
  • TERMINATED:线程执行完毕,生命周期结束。

通过以下代码示例查看线程状态:

java 复制代码
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    System.out.println("State before start: " + t1.getState());
    t1.start();
    Thread.sleep(500);
    System.out.println("State after start: " + t1.getState());
}

2.3 线程的常用方法

获取当前线程
java 复制代码
Thread current = Thread.currentThread();
System.out.println("Current thread: " + current.getName());
设置线程的优先级
java 复制代码
Thread t1 = new Thread(() -> System.out.println("Task 1"));
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
线程休眠
java 复制代码
Thread.sleep(1000);  // 让当前线程休眠1000毫秒
线程的join方法

join方法让当前线程等待,直到调用的线程执行完毕。

java 复制代码
Thread t1 = new Thread(() -> {
    System.out.println("Thread 1 is running...");
});
t1.start();
t1.join();  // 当前线程等待t1完成
相关推荐
我是唐青枫2 小时前
C#.NET struct 全解析:什么时候该用值类型?
开发语言·c#·.net
由之2 小时前
Spring事件监听机制简单使用
java·spring
小鸡吃米…2 小时前
Python - 类属性
java·前端·python
沉下去,苦磨练!2 小时前
计算一个字符串在另一个字符串中出现次数
java·开发语言
froginwe112 小时前
Bootstrap5 表格
开发语言
前端不太难2 小时前
Navigation State 驱动的页面调试方法论
开发语言·前端·react.js
饕餮怪程序猿2 小时前
订单分批算法设计与实现:基于商品相似性的智能分拣优化(C++)
开发语言·c++·算法
Li_7695322 小时前
Redis —— (五)
java·redis·后端·spring
崇山峻岭之间2 小时前
Matlab学习记录05
开发语言·学习·matlab