您的位置:首页 > 科技 > 能源 > 小广告发布_官方网站找工作公众号_郑州网站建设最便宜_自己开发网站怎么盈利

小广告发布_官方网站找工作公众号_郑州网站建设最便宜_自己开发网站怎么盈利

2025/5/9 12:51:10 来源:https://blog.csdn.net/lilinhai548/article/details/146154765  浏览:    关键词:小广告发布_官方网站找工作公众号_郑州网站建设最便宜_自己开发网站怎么盈利
小广告发布_官方网站找工作公众号_郑州网站建设最便宜_自己开发网站怎么盈利

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

深入浅出Java并发编程:线程基础

引言

在当今的软件开发领域,并发编程已经成为一项不可或缺的技能。随着多核处理器的普及,应用程序的性能优化越来越依赖于如何有效地利用多线程技术。Java作为一门成熟的编程语言,提供了丰富的并发编程工具和API,使得开发者能够轻松地构建高效、稳定的多线程应用。

然而,并发编程并非易事。它涉及到许多复杂的概念和技术,如线程安全锁机制线程通信等。对于初学者来说,理解这些概念并掌握其应用是一个不小的挑战。本文将从最基础的线程概念入手,逐步深入,帮助读者建立起对Java并发编程的全面理解。

本文将围绕以下几个核心主题展开:

  1. 进程与线程的区别与联系:理解操作系统层面的进程与线程,以及它们在Java中的具体表现。
  2. 线程的创建方式:详细介绍Java中创建线程的三种方式:继承Thread类、实现Runnable接口、以及使用CallableFuture
  3. 线程的生命周期与状态转换:深入探讨线程从创建到销毁的整个生命周期,以及各个状态之间的转换条件。
  4. 守护线程与用户线程:解释守护线程与用户线程的区别,以及它们在应用中的使用场景。
  5. 线程优先级与调度策略:探讨线程优先级的概念,以及Java虚拟机如何调度线程。

1. 进程与线程的区别与联系

1.1 进程与线程的基本概念

在操作系统中,进程线程是两个核心概念。理解它们的区别与联系是学习并发编程的基础。

  • 进程:进程是操作系统进行资源分配和调度的基本单位。每个进程都有独立的内存空间,包含了程序代码、数据、堆栈等。进程之间的通信需要通过特定的机制,如管道、消息队列、共享内存等。

  • 线程:线程是进程中的一个执行单元,是CPU调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的内存空间和资源。线程之间的通信相对简单,因为它们可以直接访问共享的内存。

1.2 进程与线程的区别

特性进程线程
资源分配独立的内存空间共享进程的内存空间
通信方式需要特定的机制(如管道、消息队列)可以直接访问共享内存
创建开销较大较小
切换开销较大较小
独立性高度独立依赖于进程

1.3 进程与线程的联系

  • 资源共享:线程共享进程的资源,如内存、文件句柄等。这使得线程之间的通信更加高效。
  • 并发执行:多个线程可以在同一个进程中并发执行,从而提高程序的执行效率。
  • 依赖关系:线程依赖于进程,进程终止时,其所有线程也会终止。

2. 线程的创建方式

在Java中,创建线程主要有三种方式:继承Thread类、实现Runnable接口、以及使用CallableFuture。下面我们将详细介绍这三种方式。

2.1 继承Thread

继承Thread类是最简单的创建线程的方式。通过重写run()方法,可以定义线程执行的任务。

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}

优点:简单直观,适合简单的任务。

缺点:由于Java不支持多继承,继承Thread类后无法再继承其他类。

2.2 实现Runnable接口

实现Runnable接口是更常用的创建线程的方式。通过实现run()方法,可以将任务与线程分离。

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
}

优点:避免了单继承的限制,适合复杂的任务。

缺点:无法直接获取线程的执行结果。

2.3 使用CallableFuture

Callable接口与Runnable接口类似,但它可以返回一个结果,并且可以抛出异常。通过Future对象,可以获取线程的执行结果。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Callable is running";}
}public class Main {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> futureTask = new FutureTask<>(new MyCallable());Thread thread = new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}

优点:可以获取线程的执行结果,适合需要返回值的任务。

缺点:使用相对复杂,需要处理Future对象。

3. 线程的生命周期与状态转换

线程的生命周期包括多个状态,理解这些状态及其转换条件对于掌握线程的行为至关重要。

3.1 线程的生命周期

Java线程的生命周期包括以下几个状态:

  • 新建(New):线程对象被创建,但尚未启动。
  • 就绪(Runnable):线程已经启动,等待CPU调度执行。
  • 运行(Running):线程正在执行run()方法。
  • 阻塞(Blocked):线程因为某些原因(如等待锁)暂时停止执行。
  • 等待(Waiting):线程无限期等待其他线程的通知。
  • 超时等待(Timed Waiting):线程在指定的时间内等待其他线程的通知。
  • 终止(Terminated):线程执行完毕或被强制终止。

3.2 状态转换

线程的状态转换可以通过以下方法触发:

  • start():将线程从新建状态转换为就绪状态。
  • yield():将线程从运行状态转换为就绪状态。
  • sleep():将线程从运行状态转换为超时等待状态。
  • wait():将线程从运行状态转换为等待状态。
  • notify()/notifyAll():将线程从等待状态转换为就绪状态。
  • join():将线程从运行状态转换为等待状态,直到目标线程终止。
  • interrupt():将线程从阻塞或等待状态转换为就绪状态。

3.3 状态跃迁图谱

start()
run()结束
竞争锁失败
获取到锁
wait()/join()
notify()/notifyAll()
sleep(n)/wait(n)
超时结束
NEW
RUNNABLE
TERMINATED
BLOCKED
WAITING
TIMED_WAITING

4. 守护线程与用户线程

特性对比

特征项用户线程守护线程
JVM退出条件全部终止不阻止退出
默认值
典型应用业务逻辑GC线程
异常处理向上传播静默失败

4.1 守护线程

守护线程是一种特殊的线程,它在后台运行,为其他线程提供服务。当所有的用户线程结束时,守护线程会自动终止。

class DaemonThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("Daemon thread is running");}}
}public class Main {public static void main(String[] args) {DaemonThread daemonThread = new DaemonThread();daemonThread.setDaemon(true);daemonThread.start();System.out.println("Main thread is finished");}
}

特点

  • 守护线程不会阻止JVM退出。
  • 守护线程通常用于执行一些后台任务,如垃圾回收、日志记录等。

4.2 用户线程

用户线程是普通的线程,它的生命周期与应用程序的生命周期一致。只有当所有的用户线程结束时,JVM才会退出。

特点

  • 用户线程的执行会影响应用程序的生命周期。
  • 用户线程通常用于执行应用程序的核心任务。

5. 线程优先级与调度策略

5.1 优先级失效实验

IntStream.rangeClosed(1, 10).forEach(i -> {Thread thread = new Thread(() -> {long count = 0;while (!Thread.interrupted()) {count++;}System.out.println(Thread.currentThread().getName() + ": " + count);});thread.setPriority(i % 2 == 0 ? Thread.MAX_PRIORITY : Thread.MIN_PRIORITY);thread.start();
});
// 观察输出结果的无序性

5.2 线程优先级

Java中的线程优先级分为10个级别,范围从1(最低)到10(最高)。默认情况下,线程的优先级为5。

class PriorityThread extends Thread {@Overridepublic void run() {System.out.println("Thread priority: " + getPriority());}
}public class Main {public static void main(String[] args) {PriorityThread thread1 = new PriorityThread();PriorityThread thread2 = new PriorityThread();thread1.setPriority(Thread.MIN_PRIORITY);thread2.setPriority(Thread.MAX_PRIORITY);thread1.start();thread2.start();}
}

注意:线程优先级只是一个提示,具体的调度策略由JVM和操作系统决定。

5.3 线程调度策略

Java的线程调度策略主要依赖于操作系统的调度算法。常见的调度策略包括:

  • 时间片轮转调度:每个线程分配一个时间片,时间片用完后切换到下一个线程。
  • 优先级调度:高优先级的线程优先执行。
  • 抢占式调度:高优先级的线程可以抢占低优先级线程的执行权。

注意:Java的线程调度是非确定性的,开发者不应依赖线程优先级来控制程序的执行顺序。

结语

通过本文的学习,我们详细探讨了Java并发编程中的线程基础,包括进程与线程的区别、线程的创建方式线程的生命周期守护线程用户线程、以及线程优先级与调度策略。掌握这些基础知识是进一步学习并发编程的关键。

在实际开发中,理解并正确使用这些概念可以帮助我们构建高效、稳定的多线程应用。然而,并发编程的复杂性远不止于此,后续我们还将深入探讨线程安全、锁机制、线程通信等高级主题。

参考资料

  1. Java Concurrency in Practice - Brian Goetz
  2. Oracle Java Documentation
  3. Java Threads and the Concurrency Utilities - Jeff Friesen
  4. Java并发编程实战 - 方腾飞

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com