当前位置: 首页 > wzjs >正文

上海宝山网站制作免费永久注册顶级域名网站

上海宝山网站制作,免费永久注册顶级域名网站,北京房山idc机房,wordpress 首页文章列表一、开篇:走进 Java 并发编程世界 在现代软件开发中,充分利用多核 CPU 的计算能力至关重要,Java 并发编程为我们提供了实现这一目标的工具。从简单的多线程任务并行执行,到复杂的高并发系统设计,掌握并发编程是进阶 Ja…

一、开篇:走进 Java 并发编程世界

        在现代软件开发中,充分利用多核 CPU 的计算能力至关重要,Java 并发编程为我们提供了实现这一目标的工具。从简单的多线程任务并行执行,到复杂的高并发系统设计,掌握并发编程是进阶 Java 工程师的关键一步。本篇作为上篇,聚焦多线程基础、线程状态、线程组与优先级、进程线程区别,以及synchronized锁的基础与状态体系 。

        先叠个甲,由于这一块内容是面试必问的部分,也是经常用的,内容太多,我分三篇逐步更新,从基础线程概念到线程池、锁等复杂场景。

二、Java 多线程入门:创建与核心逻辑

(一)创建线程的三种方式

1. 继承 Thread 类:线程逻辑内聚

        继承Thread,重写run方法定义线程执行体。调用start方法启动新线程(直接调用run是普通方法调用,不会新建线程 )。

class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName() + "执行,i=" + i);}}
}public class ThreadInheritDemo {public static void main(String[] args) {MyThread thread1 = new MyThread();thread1.setName("自定义线程1");thread1.start(); MyThread thread2 = new MyThread();thread2.setName("自定义线程2");thread2.start(); }
}

运行后,两个线程交替输出,体现多线程并发执行特性,适合线程逻辑简单且无需复用的场景。

2. 实现 Runnable 接口:解耦任务与线程

        将线程执行逻辑封装到Runnable实现类,避免单继承限制(Java 类仅能单继承,但可实现多个接口 ),方便任务逻辑复用。        

class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName() + "执行,i=" + i);}}
}public class RunnableImplDemo {public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread threadA = new Thread(runnable, "线程A");Thread threadB = new Thread(runnable, "线程B");threadA.start();threadB.start();}
}

 Runnable作为任务载体,被不同线程实例执行,常用于线程池、任务分发等场景。

3. 实现 Callable 接口:支持返回结果

  CallableRunnable类似,但call方法有返回值,需结合FutureFutureTask获取结果,适用于需线程执行产出数据的场景。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 5; i++) {sum += i;}return sum;}
}public class CallableImplDemo {public static void main(String[] args) {MyCallable callable = new MyCallable();FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask, "计算线程");thread.start();try {Integer result = futureTask.get(); System.out.println("线程计算结果:" + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

futureTask.get()会阻塞直到线程执行完毕返回结果,也可设置超时时间避免永久阻塞。

二)线程关键疑问:run 与 start、重写 run 的本质

1. 为何重写 run 方法?

  Thread类默认run方法体为空(public void run() {} ),重写run是为了定义线程实际执行的业务逻辑,让线程启动后执行我们期望的代码。

2. run 方法与 start 方法的区别
  • run 方法:普通实例方法,调用时由当前线程(调用run的线程)顺序执行run内代码,不会创建新线程。
  • start 方法Thread类特殊方法,调用后触发 JVM创建新线程,并由新线程执行run逻辑。即start是 “启动新线程 + 执行任务”,run只是 “执行任务(当前线程)” 。
class TestThread extends Thread {@Overridepublic void run() {System.out.println("当前线程名:" + Thread.currentThread().getName());}
}public class StartRunDistinguish {public static void main(String[] args) {TestThread thread = new TestThread();thread.setName("自定义线程");thread.run(); thread.start(); }
}

输出:
当前线程名:main
当前线程名:自定义线程
清晰展示两者差异,start才是真正启动新线程的方式。

三)控制线程的常用方法

1. sleep ():线程休眠

        使当前线程暂停指定时间(毫秒),让出 CPU 但不释放对象锁(若持有锁)。常用于模拟延迟、协调执行节奏。

public class SleepUsage {public static void main(String[] args) {new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName() + "执行,i=" + i);try {Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();}}}, "睡眠线程").start();}
}

线程每隔 1 秒输出,期间 CPU 可被其他线程使用,但锁资源(若涉及同步代码)不会释放。

2. join ():线程等待

让当前线程等待目标线程执行完毕后再继续,用于协调线程执行顺序。

public class JoinUsage {public static void main(String[] args) throws InterruptedException {Thread threadA = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("线程A执行,i=" + i);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}});threadA.start();threadA.join(); System.out.println("线程A执行完毕,main线程继续");}
}

 “main 线程继续” 需在线程 A 执行完 3 次循环后才输出,确保执行顺序。

其实也可以这样理解,让A线程插队,当前线程main在A线程执行完毕后再执行

3. setDaemon ():守护线程

        守护线程为用户线程服务,所有用户线程结束后,守护线程自动终止(如 JVM 的 GC 线程 )。需在start前设置。

public class DaemonUsage {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("守护线程运行中...");try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}});daemonThread.setDaemon(true); daemonThread.start();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("main线程结束");}
}

main 线程(用户线程)结束后,守护线程随之停止,不会无限循环。

4. yield ():线程让步

        当前线程主动让出 CPU 使用权,回到就绪状态重新参与调度,仅为 “建议”,不保证生效,用于给同优先级线程更多执行机会。
 

public class YieldUsage {public static void main(String[] args) {Thread thread1 = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("线程1执行,i=" + i);Thread.yield(); }});Thread thread2 = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("线程2执行,i=" + i);}});thread1.start();thread2.start();}
}

线程 1 每次循环尝试让步,线程 2 可能更频繁执行,但因调度不确定性,结果不绝对一致。

三、Java 线程的 6 种状态:生命周期全解析

Java 线程状态定义在Thread.State枚举中,共 6 种,理解状态转换对排查线程问题、优化并发逻辑至关重要。

(一)状态枚举与含义

  1. NEW(新建):线程对象已创建(如new Thread() ),但未调用start,未启动。
  2. RUNNABLE(可运行):线程已启动(start调用后),可能正在 CPU 执行,或在就绪队列等待调度,也就是就绪状态。
  3. BLOCKED(阻塞):线程竞争synchronized锁失败,进入阻塞态,等待锁释放。
  4. WAITING(等待):线程调用Object.wait()(无超时)、Thread.join()(无超时)、LockSupport.park()等,无时限等待唤醒。
  5. TIMED_WAITING(计时等待):调用Thread.sleep(long)Object.wait(long)Thread.join(long) 、LockSupport.parkNanos/parkUntil等,限时等待,超时自动唤醒。
  6. TERMINATED(终止):线程执行完毕(run正常结束或抛未捕获异常),生命周期结束。

(二)状态转换示例

通过代码观察线程从新建到终止的状态变化:

public class ThreadStateAnalysis {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {try {Thread.sleep(1500); synchronized (ThreadStateAnalysis.class) {System.out.println("线程执行中,获取锁");}} catch (InterruptedException e) {e.printStackTrace();}});System.out.println("线程状态(NEW):" + thread.getState()); thread.start();Thread.sleep(500); System.out.println("线程状态(TIMED_WAITING):" + thread.getState()); Thread.sleep(1500); System.out.println("线程状态(RUNNABLE/执行中):" + thread.getState()); thread.join(); System.out.println("线程状态(TERMINATED):" + thread.getState()); }
}

         结合getState()与线程执行逻辑,可清晰看到状态NEWTIMED_WAITINGRUNNABLETERMINATED的流转。实际调试中,可借助 JConsole、VisualVM 等工具直观分析复杂状态切换。

四、线程组与线程优先级:管理与调度辅助

(一)线程组(ThreadGroup)

        线程组用于批量管理线程,可统一设置优先级、捕获未处理异常等。默认情况下,新建线程加入创建它的线程所在组(通常是main线程组 )。

public class ThreadGroupManagement {public static void main(String[] args) {ThreadGroup customGroup = new ThreadGroup("自定义线程组");Thread thread1 = new Thread(customGroup, () -> {System.out.println("线程1所属组:" + Thread.currentThread().getThreadGroup().getName());}, "线程1");Thread thread2 = new Thread(customGroup, () -> {System.out.println("线程2所属组:" + Thread.currentThread().getThreadGroup().getName());}, "线程2");thread1.start();thread2.start();Thread[] threads = new Thread[customGroup.activeCount()];customGroup.enumerate(threads);for (Thread t : threads) {System.out.println("线程组线程:" + t.getName());}}
}

线程组辅助批量操作,但现代并发更依赖线程池,线程组使用场景逐渐减少,了解即可。

(二)线程优先级:调度 “建议”

        线程优先级是调度器优先调度的 “建议”,范围 1(最低)~10(最高),默认 5。优先级高的线程理论上获取 CPU 时间片机会更多,但不保证执行顺序(受操作系统调度策略影响 )。

public class ThreadPriorityControl {public static void main(String[] args) {Thread highPriority = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("高优先级线程执行,i=" + i);}});highPriority.setPriority(Thread.MAX_PRIORITY); Thread lowPriority = new Thread(() -> {for (int i = 0; i < 3; i++) {System.out.println("低优先级线程执行,i=" + i);}});lowPriority.setPriority(Thread.MIN_PRIORITY); highPriority.start();lowPriority.start();}
}

        多次运行可能观察到高优先级线程更 “活跃”,但因系统调度不确定性,不能完全依赖优先级控制执行顺序,实际开发需谨慎使用。

五、进程与线程的区别:资源与执行单元

(一)核心差异对比

对比维度
进程
线程
资源分配单位操作系统分配资源(内存、文件句柄等)的基本单位进程内的执行单元,CPU 调度的基本单位
资源占用独立地址空间,资源消耗大共享进程资源(内存、文件描述符等),消耗小
上下文切换成本高(需切换地址空间、寄存器等)
低(主要切换寄存器、程序计数器)
通信复杂度进程间通信复杂(IPC:管道、socket 等)线程间通信简单(共享内存)
独立性进程间相互独立,一个崩溃不影响其他进程线程同属进程,一个崩溃可能致进程崩溃

(二)通俗类比

以 “在线文档编辑应用” 为例:

  • 进程:整个应用是进程,操作系统为其分配独立内存,存储代码、用户数据等,是资源隔离的单位。
  • 线程:拼写检查、自动保存、实时协作同步等功能,作为线程共享进程内存,协作完成任务。若拼写检查线程崩溃,可能导致整个应用(进程)异常,体现线程对进程的依赖。

 

六、synchronized 关键字:锁的基础与状态体系

(一)锁的基本认知:基于对象的锁

        Java 中每个对象均可作为锁,常说的 “类锁” 本质是Class对象的锁(Class对象在 JVM 加载类时创建,唯一对应类元数据 )。通过synchronized实现同步,保障多线程下共享资源的原子性、可见性。

(二)synchronized 的三种使用形式

1. 同步实例方法(锁当前对象)
        银行账户(Account)有一个withdraw方法,一个人在不同设备上同时取钱,多线程可能同时取款,需保证余额正确。

代码示例

public class Account {private double balance;public Account(double balance) {this.balance = balance;}// 同步实例方法:锁当前对象(this)public synchronized void withdraw(double amount) {if (balance >= amount) {try {Thread.sleep(100); // 模拟业务耗时} catch (InterruptedException e) {e.printStackTrace();}balance -= amount;System.out.println(Thread.currentThread().getName() + "取款成功,余额:" + balance);} else {System.out.println(Thread.currentThread().getName() + "取款失败,余额不足");}}
}
  • 锁的是当前对象(this),若多个线程操作同一对象,会互斥。
  • 若多个线程操作不同对象,则互不影响(每个对象有独立的锁)。
2. 同步静态方法(锁类对象)
统计网站访问量(静态变量visitCount),多线程并发访问需保证计数正确。

代码示例

public class WebSite {private static int visitCount = 0;// 同步静态方法:锁类对象(WebSite.class)public static synchronized void incrementVisit() {visitCount++;System.out.println(Thread.currentThread().getName() + "访问,总访问量:" + visitCount);}
}
  • 锁的是类的Class对象(全局唯一),无论创建多少实例,所有线程都会互斥。
  • 适合保护静态共享资源(如全局计数器、配置信息)。
3. 同步代码块

电商系统中,商品库存(stock)和订单号生成器(orderIdGenerator)需分别加锁。

代码示例:

public class ShoppingSystem {private int stock = 10;private static final Object STOCK_LOCK = new Object(); // 库存锁private static final Object ORDER_LOCK = new Object(); // 订单号锁private static int orderId = 0;// 扣减库存public void reduceStock() {synchronized (STOCK_LOCK) { // 锁库存专用对象if (stock > 0) {stock--;System.out.println(Thread.currentThread().getName() + "扣减库存成功,剩余:" + stock);} else {System.out.println(Thread.currentThread().getName() + "库存不足");}}}// 生成订单号public static void generateOrderId() {synchronized (ORDER_LOCK) { // 锁订单号专用对象orderId++;System.out.println(Thread.currentThread().getName() + "生成订单号:" + orderId);}}
}
  • 锁对象可以是任意Object,推荐使用private static final修饰,避免外部访问。
  • 缩小锁的范围,提高并发性能(如只锁需要保护的代码,而非整个方法)。

结合场景更容易理解,注意理解,而非死记硬背 

(三)synchronized 的四种锁状态

        JVM 对synchronized锁进行优化,存在四种状态:偏向锁、轻量级锁、重量级锁、无锁,状态随竞争情况升级(不能降级,单向升级 )。

后面的内容我们在下一篇中讲....

http://www.dtcms.com/wzjs/33340.html

相关文章:

  • 手机网站怎么做微信登陆慧聪网seo页面优化
  • 如何在国外网站做免费推广游戏推广接单平台
  • 信息网站建设的意义网站搭建的流程
  • 三亚网站建设哪家好成都纯手工seo
  • 美橙互联的网站日志在哪里下载百度一下百度一下你就知道
  • 深圳建设厅网站官网360指数在线查询
  • 潍坊seo网站推广seo网站内容优化有哪些
  • 网站开发工具webs深圳疫情防控最新消息
  • 深圳官网网站建设专业seo站长工具
  • 房产网站源码wordpress活动策划
  • 西宁高端网站制作公司厦门网站搜索引擎优化
  • 做汽车新闻哪个网站好谷歌商店paypal官网下载
  • ppt资源网免费仁茂网络seo
  • 网站建设免费加盟代理微信怎么推广引流客户
  • 对网站建设和维护好学吗百度地图关键词排名优化
  • 去掉 wordpress.org关键词优化的建议
  • 保定专门做网站的公司太原seo全网营销
  • h5响应式企业网站源码亚马逊seo推广
  • 微信怎么做链接网站做网站优化哪家公司好
  • 世界杯直播观看网站seo单页快速排名
  • .xyz做网站怎么样百度爱采购竞价推广
  • 土地流转网站建设项目百度学术免费查重入口
  • 网站总体规划设计说明百度搜索引擎优化怎么做
  • 建个网站花钱做百度推广dy刷粉网站推广马上刷
  • 公司网站备案需要什么全网营销网络推广
  • 网站编程培训班搜索引擎优化实训
  • 电商网站开发的目的和意义比较靠谱的网站
  • 银行网站开发关键词竞价排名是什么意思
  • 互联网大赛建设网站策划书河南网站建设报价
  • 石家庄官网设计及搭建浙江seo推广