Java多线程知识点

Java多线程是并发编程的一种形式,它允许在一个程序中同时运行多个线程。每个线程都是程序执行流,拥有自己的堆栈和程序计数器,但共享程序的其他部分(如内存和静态变量)。

一、线程与进程

  • 进程:程序运行资源分配的最小单位。进程有自己的独立地址空间,系统为它分配地址空间并建立数据表来维护代码段、堆栈段和数据段。
  • 线程:CPU调度的最小单位,必须依赖进程而存在。线程共享进程中的资源,使用相同的地址空间,因此CPU切换线程的开销比进程小。

    二、线程的实现方式

1. 继承Thread类

通过继承Thread类并重写其run()方法来实现多线程。但Java只支持单继承,因此这种方式有一定的局限性。

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的代码
    }
}

### 2. 实现Runnable接口

实现Runnable接口并重写其run()方法,然后将Runnable对象传递给Thread对象。这种方式更为灵活,因为可以实现多个接口。

```java
class MyRunnable implements Runnable {
    @Override
    public void run() {        // 线程执行的代码
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();

3. 实现Callable接口

与Runnable接口类似,但Callable接口允许线程任务有返回值,并且可以抛出异常。配合Future获取线程的执行结果。

import java.util.concurrent.*;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 线程执行的代码,返回整数结果
        return 1;
    }
}

Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
Integer result = futureTask.get(); // 获取线程执行结果

4. 线程池

线程池提供了一种管理和复用线程的机制,减少了线程的创建和销毁开销,提高了程序的性能。Java提供了多种线程池实现,如FixedThreadPool、CachedThreadPool和ScheduledThreadPool等。

ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(new RunnableTask()); // 提交任务给线程池
executorService.shutdown(); // 关闭线程池

三、线程的生命周期

Java中的线程具有多种状态,包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)。线程在其生命周期中会在这些状态之间转换。

  • 新建状态:线程对象被创建,但尚未调用start()方法。
  • 就绪状态:线程调用start()方法后进入就绪状态,等待CPU调度。
  • 运行状态:线程获得CPU,开始执行run()方法
  • 阻塞状态:线程因为某些原因(如sleep、wait、join等)暂时停止运行。
  • 死亡状态:线程的run()方法执行完毕或被强制终止。

四、线程同步与线程安全

由于多个线程共享程序的资源,因此需要对这些资源进行同步以防止数据不一致或冲突。Java提供了多种同步机制来确保线程安全。

1. synchronized关键字

可以使用synchronized关键字来修饰方法或代码块,从而实现线程同步。

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

2. Lock接口

Lock接口提供了比synchronized更灵活的同步机制,支持显式加锁和解锁。常用的实现类有ReentrantLock。

import java.util.concurrent.locks.ReentrantLock;
class Counter    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();
    public void increment() {
        lock.lock();
        try            count++;
        } finally {
            lock.unlock();
        }
    }
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

五、其他重要概念

  • 守护线程:守护线程是一种特殊的线程,当主线程结束时,守护线程也会自动结束。可以通过setDaemon(true)方法将线程设置为守护线程。
  • ThreadLocal:ThreadLocal为变量在每个线程中都创建了一个副本,使得每个线程都可以访问自己内部的副本变量,从而实现线程隔离。
  • CAS操作:CAS(Compare And Swap)是一种原子操作,用于实现无锁算法。它可以有效地提升并发的效率,但同时也会引入ABA问题。