当前位置:   article > 正文

Java入门至精通:多线程与并发编程_精通 多线程

精通 多线程

目录

一 线程的概念与创建方式

A.Java线程的概念

B.Java线程的创建方式

a.继承Thread类:

b.实现Runnable接口:

c.使用lambda表达式:

d.使用Executor框架:

二 线程同步与锁机制

A.同步(Synchronization)

B. 锁机制


一 线程的概念与创建方式

A.Java线程的概念

在Java中,线程(Thread)是程序执行流的最小单元,代表着程序中的单一顺序控制流程。一个Java应用程序通常由一个或多个线程组成,这些线程可以并发地执行,从而实现多任务并行处理,提高程序的执行效率和响应速度。

线程具备以下特性:

  1. 并发执行:多个线程可以在同一应用程序中同时运行,共享相同的进程资源(如内存、文件等),但各自独立执行特定任务。

  2. 轻量级进程:相比于操作系统的进程,线程是更轻量级的执行单元,创建和切换线程的开销较小,适合用于实现高并发、高响应的程序。

  3. 共享与隔离:线程之间可以共享进程资源,如全局变量、静态变量等。同时,每个线程拥有自己的程序计数器、栈内存(保存局部变量和方法调用信息)和线程本地存储(ThreadLocal),保证了线程间的相对独立性。

  4. 同步与通信:为了协调多个线程对共享资源的访问,Java提供了多种同步机制(如synchronized关键字、Lock接口等)以及通信手段(如wait/notify、Condition、BlockingQueue等),确保数据一致性,避免竞态条件和死锁等问题。

B.Java线程的创建方式

Java提供了多种创建线程的方法,包括:

a.继承Thread类

创建一个新的类,继承自java.lang.Thread,并重写其run()方法,定义线程执行的具体逻辑。然后创建该类的实例并调用start()方法启动线程。

  1. class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. // 线程执行的代码
  5. }
  6. }
  7. MyThread thread = new MyThread();
  8. thread.start();
b.实现Runnable接口

创建一个类,实现java.lang.Runnable接口,实现run()方法。然后将该实例作为参数传递给Thread类的构造器创建线程对象,并调用start()方法启动线程。

  1. class Task implements Runnable {
  2. @Override
  3. public void run() {
  4. // 线程执行的代码
  5. }
  6. }
  7. Thread thread = new Thread(new Task());
  8. thread.start();
c.使用lambda表达式

对于简单的线程任务,可以直接使用lambda表达式创建并启动线程,无需定义额外的类。这种方法本质上还是实现了Runnable接口。

  1. Thread thread = new Thread(() -> {
  2. // 线程执行的代码
  3. });
  4. thread.start();
d.使用Executor框架

Java 5引入了java.util.concurrent包,其中的Executor框架提供了更高级的线程管理和控制机制。通过创建ExecutorService实例(如ThreadPoolExecutorScheduledThreadPoolExecutor),提交RunnableCallable任务,框架负责线程的创建、调度和管理。

  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;
  3. ExecutorService executor = Executors.newSingleThreadExecutor();
  4. executor.submit(() -> {
  5. // 线程执行的代码
  6. });
  7. // 不再接受新任务并等待现有任务完成后关闭executor
  8. executor.shutdown();

选择合适的线程创建方式取决于具体的应用场景和需求。直接继承Thread类或实现Runnable接口适用于简单、独立的任务;lambda表达式简化了代码编写;而Executor框架提供了线程池、任务调度、异常处理等更强大的功能,适用于复杂的并发编程场景。

二 线程同步与锁机制

Java线程同步与锁机制是为了解决多线程环境下对共享资源进行访问时可能出现的数据不一致、竞态条件和死锁等问题。通过同步和锁机制,可以确保在某一时刻,只有一个线程能够访问特定的临界区(critical section),从而维护数据的完整性。

A.同步(Synchronization)

同步是Java中控制多个线程对共享资源访问的一种机制。主要有以下两种实现方式:

  • synchronized关键字

    • 同步方法:在方法声明中添加synchronized关键字,使得该方法变为同步方法。当一个线程访问同步方法时,其他试图访问该方法的线程会被阻塞,直到该方法执行完毕,释放锁。
    • 同步代码块:使用synchronized修饰特定的对象实例,将需要同步的代码块包围起来。线程在访问该同步代码块前必须获得该对象的锁,其他线程必须等待锁释放后才能进入。
  1. public class Counter {
  2. private int count = 0;
  3. // 同步方法
  4. public synchronized void increment() {
  5. count++;
  6. }
  7. // 同步代码块
  8. public void decrement() {
  9. synchronized (this) {
  10. count--;
  11. }
  12. }
  13. }

Lock接口与相关类

  • ReentrantLockjava.util.concurrent.locks.ReentrantLock类提供了比synchronized更灵活的锁机制,支持公平锁、非公平锁、可中断锁、尝试锁等特性。通过lock()方法获取锁,unlock()方法释放锁。
  1. import java.util.concurrent.locks.ReentrantLock;
  2. public class Counter {
  3. private final ReentrantLock lock = new ReentrantLock();
  4. private int count = 0;
  5. public void increment() {
  6. lock.lock();
  7. try {
  8. count++;
  9. } finally {
  10. lock.unlock();
  11. }
  12. }
  13. public void decrement() {
  14. lock.lock();
  15. try {
  16. count--;
  17. } finally {
  18. lock.unlock();
  19. }
  20. }
  21. }

B. 锁机制

Java中的锁机制主要包括以下几种:

  • 内置锁(Intrinsic Locks):即synchronized关键字隐含的锁,每个Java对象都有一个内置锁,当一个线程访问对象的synchronized方法或代码块时,会自动获得该对象的内置锁。

  • ReentrantLock:如上所述,它是一个可重入的互斥锁,支持更多的高级特性,如公平锁、条件变量(Condition)、锁超时等。

  • 读写锁(ReadWriteLock)java.util.concurrent.locks.ReadWriteLock接口及其实现类ReentrantReadWriteLock提供了读写分离的锁机制。多个读线程可以同时访问资源,而写线程在写入时会排斥所有读写线程,提高读多写少场景下的并发性能。

  1. import java.util.concurrent.locks.ReadWriteLock;
  2. import java.util.concurrent.locks.ReentrantReadWriteLock;
  3. public class ConcurrentDictionary {
  4. private final ReadWriteLock lock = new ReentrantReadWriteLock();
  5. private final Map<String, String> dictionary = new HashMap<>();
  6. public String get(String key) {
  7. lock.readLock().lock();
  8. try {
  9. return dictionary.get(key);
  10. } finally {
  11. lock.readLock().unlock();
  12. }
  13. }
  14. public void put(String key, String value) {
  15. lock.writeLock().lock();
  16. try {
  17. dictionary.put(key, value);
  18. } finally {
  19. lock.writeLock().unlock();
  20. }
  21. }
  22. }
  • tampedLock:提供乐观读锁、悲观写锁和悲观读写锁,支持在读多写少的场景下进行更细粒度的控制,提高并发性能。

  • Semaphore:信号量,用于控制同时访问特定资源的线程数量。

  • 其他并发工具类:如CyclicBarrierCountDownLatch等,虽然不是典型的锁,但用于多线程间的同步控制。

总的来说,Java的线程同步与锁机制为多线程编程提供了丰富的工具,帮助开发者有效地管理共享资源的并发访问,确保数据的一致性和正确性,同时兼顾性能优化。在实际应用中,应根据具体场景选择合适的同步工具或锁机制。

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

闽ICP备14008679号