当前位置:   article > 正文

Java 多线程编程教程:从入门到精通_java多线程编程技术

java多线程编程技术

Java 多线程编程教程:从入门到精通

一、 前言

多线程是 Java 编程中一项重要的技术,它允许程序同时执行多个任务,从而提高程序效率和响应速度。本教程将带你从基础知识到高级应用,全面掌握 Java 多线程编程。

二、 基础知识

  • 线程的概念: 线程是进程中的一个执行单元,它可以独立运行,拥有自己的栈空间和程序计数器。一个进程可以包含多个线程,这些线程共享进程的内存空间和资源。
  • 多线程的优势:
    • 提高程序效率: 多个线程可以同时执行不同的任务,充分利用CPU资源,提升程序运行速度。
    • 增强用户体验: 例如,在 GUI 程序中,可以使用多个线程分别处理用户交互、数据处理等任务,避免程序阻塞,提升用户体验。
    • 提高资源利用率: 多线程可以共享进程的资源,避免重复创建和销毁资源,提高资源利用率。
  • 线程的生命周期:
    • 新建(New): 线程被创建后,尚未启动。
    • 可运行(Runnable): 线程已创建,等待 CPU 时间片分配。
    • 运行(Running): 线程正在执行。
    • 阻塞(Blocked): 线程处于等待状态,例如等待锁、输入输出操作等。
    • 终止(Terminated): 线程执行完毕,或者因异常而结束。

三、 创建和启动线程

1. 继承 Thread 类:

public class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的代码
        System.out.println("线程正在运行...");
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2. 实现 Runnable 接口:

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的代码
        System.out.println("线程正在运行...");
    }

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start(); // 启动线程
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

四、 线程同步

  • 同步问题: 多个线程同时访问共享资源时,可能出现数据不一致的情况,例如多个线程同时修改同一个变量。
  • 解决方法: 使用同步机制,例如锁(synchronized关键字,ReentrantLock)和信号量(Semaphore)等。

1. synchronized 关键字:

public class Counter {
    private int count = 0;

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

public class MyThread extends Thread {
    private Counter counter;

    public MyThread(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            counter.increment();
        }
    }

    public static void main(String[] args) {
        Counter counter = new Counter();
        MyThread thread1 = new MyThread(counter);
        MyThread thread2 = new MyThread(counter);
        thread1.start();
        thread2.start();
        // 等待两个线程执行完毕
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("count: " + counter.count);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

2. ReentrantLock:

import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

// 其他代码与上面类似
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

五、 线程通信

  • 线程之间相互协作: 线程之间需要进行通信,例如一个线程等待另一个线程完成任务,或者一个线程向另一个线程发送消息。
  • 方法:
    • wait() 和 notify() 方法: 用于线程之间的阻塞和唤醒。
    • BlockingQueue: 用于线程之间安全地传递数据。
    • Condition: 用于创建多个等待队列,实现更灵活的线程通信。

1. wait() 和 notify() 方法:

public class ProducerConsumer {
    private Object lock = new Object();
    private boolean hasData = false;
    private String data;

    public void produce(String data) {
        synchronized (lock) {
            while (hasData) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.data = data;
            hasData = true;
            lock.notify();
        }
    }

    public String consume() {
        synchronized (lock) {
            while (!hasData) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            hasData = false;
            lock.notify();
            return data;
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        Thread producer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.produce("数据" + i);
            }
        });
        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("消费数据: " + pc.consume());
            }
        });
        producer.start();
        consumer.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

2. BlockingQueue:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ProducerConsumer {
    private BlockingQueue<String> queue = new LinkedBlockingQueue<>();

    public void produce(String data) {
        try {
            queue.put(data);
            System.out.println("生产数据: " + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public String consume() {
        try {
            String data = queue.take();
            System.out.println("消费数据: " + data);
            return data;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        Thread producer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.produce("数据" + i);
            }
        });
        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.consume();
            }
        });
        producer.start();
        consumer.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

3. Condition:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
    private ReentrantLock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
    private int count = 0;
    private int capacity = 10;

    public void produce(String data) {
        lock.lock();
        try {
            while (count == capacity) {
                notFull.await();
            }
            // 生产数据
            count++;
            notEmpty.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public String consume() {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            // 消费数据
            count--;
            notFull.signal();
            return "数据";
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        Thread producer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.produce("数据" + i);
            }
        });
        Thread consumer = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("消费数据: " + pc.consume());
            }
        });
        producer.start();
        consumer.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

六、 线程池

  • 线程池的优势:
    • 减少创建和销毁线程的开销: 线程池可以复用线程,避免频繁创建和销毁线程,提高效率。
    • 控制线程数量: 可以根据系统资源限制,控制线程池的大小,避免线程过多导致资源耗尽。
    • 管理线程: 线程池可以管理线程的生命周期,提供线程监控和管理功能。

1. ThreadPoolExecutor:

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 提交任务
        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                System.out.println("线程正在执行任务...");
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

七、 线程安全类

  • Java 提供了一些线程安全的类,例如:
    • AtomicInteger: 线程安全的整数类,提供原子操作。
    • AtomicLong: 线程安全的 long 类型类。
    • AtomicBoolean: 线程安全的 boolean 类型类。
    • ConcurrentHashMap: 线程安全的 HashMap。
    • CopyOnWriteArrayList: 线程安全的 ArrayList,写操作会创建一个新的数组。

八、 高级应用

  • 多线程编程的常见模式:
    • 生产者-消费者模式: 一个或多个生产者线程将数据写入共享队列,一个或多个消费者线程从队列中取出数据进行处理。
    • 线程池模式: 创建一个线程池,将任务提交到线程池中执行,线程池会自动管理线程的生命周期。
    • 工作者线程模式: 创建多个工作者线程,将任务分发给工作者线程执行,每个工作者线程都从任务队列中获取任务并执行。
  • 并行计算: 使用多线程进行并行计算,可以大幅提高计算效率。
  • 异步编程: 使用异步编程,可以提高程序的响应速度,例如使用 Future 类或 Callable 接口。

九、 总结

Java 多线程编程是一项复杂但强大的技术,它可以提高程序效率、增强用户体验、提升资源利用率。本教程介绍了 Java 多线程编程的基础知识、线程同步、线程通信、线程池以及高级应用。希望这篇文章能帮助你更好地理解和应用 Java 多线程编程。

十、 练习

  • 创建一个模拟银行账户的程序,使用多线程模拟多个用户同时存取款。
  • 创建一个模拟餐厅点餐的程序,使用多线程模拟厨师、服务员和顾客。
  • 创建一个使用线程池进行图片处理的程序,例如批量压缩或裁剪图片。

十一、 参考资料

  • Java Concurrency in Practice
  • Java 并发编程实战
  • Java 官方文档

最后,希望你能通过学习这篇文章,对 Java 多线程编程有一个更深入的了解,并在实际开发中灵活运用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/926154
推荐阅读
相关标签
  

闽ICP备14008679号