【Java】 多线程编程讲解

Java 中的多线程是一个非常重要且复杂的主题。多线程允许程序同时执行多个任务,提高了应用程序的性能和响应速度。多线程编程涉及线程的创建、管理、同步和通信等多个方面。下面我将详细讲解 Java 多线程的使用。

1. 什么是线程?

线程是程序执行的最小单位,一个进程可以包含多个线程,每个线程可以执行不同的任务。线程之间共享进程的资源,但每个线程都有自己的执行栈和程序计数器。

2. 创建线程的方式

在 Java 中,有两种主要的方式来创建线程:

2.1 继承 Thread

通过继承 Thread 类并重写其 run() 方法,可以创建一个新的线程。

  • 示例

    class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is running");
            }
        }
    }
    
    public class ThreadExample {
        public static void main(String[] args) {
            MyThread thread1 = new MyThread();
            MyThread thread2 = new MyThread();
    
            thread1.start(); // 启动线程
            thread2.start();
        }
    }
    
2.2 实现 Runnable 接口

另一种更常用的创建线程的方式是实现 Runnable 接口,并将其传递给 Thread 对象。

  • 示例

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is running");
            }
        }
    }
    
    public class RunnableExample {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
            Thread thread1 = new Thread(myRunnable);
            Thread thread2 = new Thread(myRunnable);
    
            thread1.start(); // 启动线程
            thread2.start();
        }
    }
    

3. 线程的生命周期

线程的生命周期包括以下几个阶段:

  1. 新建 (New):线程对象被创建,但尚未调用 start() 方法。
  2. 就绪 (Runnable):调用 start() 方法后,线程进入就绪状态,等待 CPU 调度执行。
  3. 运行 (Running):线程被 CPU 调度执行,run() 方法开始执行。
  4. 阻塞 (Blocked):线程因等待某些条件(如资源、锁)暂时挂起,等待条件满足后进入就绪状态。
  5. 终止 (Terminated):线程的 run() 方法执行完毕或因异常退出,线程进入终止状态。

4. 线程的控制

4.1 join() 方法

join() 方法允许一个线程等待另一个线程完成。

  • 示例

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " is running");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class JoinExample {
        public static void main(String[] args) {
            Thread thread1 = new Thread(new MyRunnable());
            Thread thread2 = new Thread(new MyRunnable());
    
            thread1.start();
            try {
                thread1.join(); // main 线程等待 thread1 执行完毕
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread2.start();
        }
    }
    
4.2 sleep() 方法

sleep() 方法使当前线程暂停执行一段时间,让出 CPU 资源,但线程仍保持就绪状态。

  • 示例

    public class SleepExample {
        public static void main(String[] args) {
            Runnable runnable = () -> {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        Thread.sleep(1000); // 暂停 1 秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            Thread thread = new Thread(runnable);
            thread.start();
        }
    }
    
4.3 interrupt() 方法

interrupt() 方法用于中断线程,通知其停止执行。

  • 示例

    public class InterruptExample {
        public static void main(String[] args) {
            Thread thread = new Thread(() -> {
                try {
                    while (!Thread.currentThread().isInterrupted()) {
                        System.out.println("Thread is running");
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    System.out.println("Thread was interrupted");
                }
            });
    
            thread.start();
            try {
                Thread.sleep(3000); // main 线程暂停 3 秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread.interrupt(); // 中断线程
        }
    }
    

5. 线程同步

多线程环境下,如果多个线程同时访问共享资源,可能会引发数据不一致的问题。这种情况下,需要使用线程同步技术。

5.1 synchronized 关键字

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();
    
            Runnable task = () -> {
                for (int i = 0; i < 1000; i++) {
                    counter.increment();
                }
            };
    
            Thread thread1 = new Thread(task);
            Thread thread2 = new Thread(task);
    
            thread1.start();
            thread2.start();
    
            thread1.join();
            thread2.join();
    
            System.out.println("Final count: " + counter.getCount());
        }
    }
    
5.2 volatile 关键字

volatile 关键字用于确保线程每次读取变量值时,都是从主存中读取,保证了变量的可见性。

  • 示例

    class VolatileExample {
        private volatile boolean flag = true;
    
        public void run() {
            while (flag) {
                System.out.println("Thread is running");
            }
        }
    
        public void stop() {
            flag = false;
        }
    
        public static void main(String[] args) throws InterruptedException {
            VolatileExample example = new VolatileExample();
    
            Thread thread = new Thread(example::run);
            thread.start();
    
            Thread.sleep(1000);
            example.stop(); // 停止线程
        }
    }
    

6. 高级并发工具

Java 提供了一些高级并发工具类,这些类位于 java.util.concurrent 包中,常见的包括:

6.1 ExecutorService

ExecutorService 是 Java 提供的一个线程池框架,方便管理和复用线程。

  • 示例

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ExecutorServiceExample {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(2);
    
            Runnable task = () -> {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            executorService.submit(task);
            executorService.submit(task);
    
            executorService.shutdown(); // 关闭线程池
        }
    }
    
6.2 CallableFuture

Callable 接口类似于 Runnable,但它可以返回结果,并且可以抛出异常。Future 接口用于表示 Callable 任务的异步执行结果。

  • 示例

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class CallableExample {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
    
            Callable<Integer> callable = () -> {
                Thread.sleep(2000);
                return 42;
            };
    
            Future<Integer> future = executorService.submit(callable);
    
            try {
                System.out.println("Future result: " + future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
    
            executorService.shutdown();
        }
    }
    
6.3 CountDownLatch

CountDownLatch 是一个同步工具类,它允许一个或多个线程

等待其他线程完成操作。

  • 示例

    import java.util.concurrent.CountDownLatch;
    
    public class CountDownLatchExample {
        public static void main(String[] args) throws InterruptedException {
            int count = 3;
            CountDownLatch latch = new CountDownLatch(count);
    
            Runnable task = () -> {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " has finished.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            };
    
            for (int i = 0; i < count; i++) {
                new Thread(task).start();
            }
    
            latch.await(); // 等待所有线程完成
            System.out.println("All threads have finished.");
        }
    }
    

7. 总结

Java 多线程编程是一个复杂但非常强大的工具。通过线程,你可以实现并发任务,提升程序的效率。然而,线程带来的并发问题(如死锁、资源竞争等)也是编程中需要特别注意的部分。掌握线程的基本操作、同步方法和高级并发工具,可以让你在开发高性能应用程序时得心应手。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值