跳转至

Java 线程全解析

简介

在 Java 编程中,线程(Threads)是实现多任务处理的关键机制。通过使用线程,程序可以同时执行多个任务,从而提高程序的性能和响应能力。本文将全面介绍 Java 线程的基础概念、使用方法、常见实践以及最佳实践,帮助读者深入理解并高效使用 Java 线程。

目录

  1. 基础概念
    • 什么是线程
    • 线程与进程的区别
    • Java 线程模型
  2. 使用方法
    • 继承 Thread 类
    • 实现 Runnable 接口
    • 使用 Callable 和 Future
  3. 常见实践
    • 线程同步
    • 线程池的使用
    • 线程间通信
  4. 最佳实践
    • 避免死锁
    • 合理使用线程池
    • 异常处理
  5. 小结
  6. 参考资料

基础概念

什么是线程

线程是程序执行的最小单位,它是进程中的一个执行流。一个进程可以包含多个线程,这些线程可以并发执行,共享进程的资源。

线程与进程的区别

  • 进程:是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程都有自己独立的内存空间和系统资源。
  • 线程:是进程中的一个执行单元,是 CPU 调度和分派的基本单位。线程共享进程的内存空间和系统资源。

Java 线程模型

在 Java 中,线程是通过 java.lang.Thread 类来表示的。Java 提供了丰富的 API 来创建、启动和管理线程。

使用方法

继承 Thread 类

通过继承 Thread 类,并重写 run() 方法来定义线程的执行逻辑。

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

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

实现 Runnable 接口

实现 Runnable 接口,并实现 run() 方法,然后将其作为参数传递给 Thread 类的构造函数。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable is running.");
    }
}

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

使用 Callable 和 Future

Callable 接口类似于 Runnable 接口,但它可以返回一个结果。使用 Future 可以获取 Callable 任务的执行结果。

import java.util.concurrent.*;

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 1 + 2;
    }
}

public class CallableExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        MyCallable callable = new MyCallable();
        Future<Integer> future = executor.submit(callable);
        Integer result = future.get();
        System.out.println("Result: " + result);
        executor.shutdown();
    }
}

常见实践

线程同步

当多个线程访问共享资源时,可能会出现数据不一致的问题。可以使用 synchronized 关键字来实现线程同步。

class Counter {
    private int count = 0;

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

    public int getCount() {
        return count;
    }
}

public class SynchronizedExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Count: " + counter.getCount());
    }
}

线程池的使用

线程池可以管理和复用线程,减少线程创建和销毁的开销。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println("Task is running.");
    }
}

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 5; i++) {
            executor.submit(new Task());
        }
        executor.shutdown();
    }
}

线程间通信

可以使用 wait()notify()notifyAll() 方法来实现线程间的通信。

class Message {
    private String msg;
    private boolean empty = true;

    public synchronized String read() {
        while (empty) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        empty = true;
        notifyAll();
        return msg;
    }

    public synchronized void write(String msg) {
        while (!empty) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        empty = false;
        this.msg = msg;
        notifyAll();
    }
}

public class ThreadCommunicationExample {
    public static void main(String[] args) {
        Message msg = new Message();
        Thread writer = new Thread(new Writer(msg));
        Thread reader = new Thread(new Reader(msg));
        writer.start();
        reader.start();
    }
}

class Writer implements Runnable {
    private Message msg;

    public Writer(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        String messages[] = {"Message 1", "Message 2", "Message 3"};
        for (String message : messages) {
            msg.write(message);
        }
    }
}

class Reader implements Runnable {
    private Message msg;

    public Reader(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(msg.read());
        }
    }
}

最佳实践

避免死锁

死锁是指两个或多个线程相互等待对方释放资源的情况。可以通过避免嵌套锁、按顺序获取锁等方法来避免死锁。

合理使用线程池

根据实际需求选择合适的线程池类型,避免创建过多的线程导致系统资源耗尽。

异常处理

在线程中捕获和处理异常,避免异常导致线程意外终止。

class MyTask implements Runnable {
    @Override
    public void run() {
        try {
            // 任务代码
        } catch (Exception e) {
            System.err.println("Exception in thread: " + e.getMessage());
        }
    }
}

小结

本文全面介绍了 Java 线程的基础概念、使用方法、常见实践以及最佳实践。通过继承 Thread 类、实现 Runnable 接口或使用 CallableFuture 可以创建线程。线程同步、线程池的使用和线程间通信是常见的线程实践。在使用线程时,需要注意避免死锁、合理使用线程池和进行异常处理。

参考资料

  • 《Effective Java》
  • Java 官方文档
  • 《Java 并发编程实战》