尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Java基础补缺2

Java基础补缺2
📅 发布时间:2026/6/21 20:54:39

Java基础补缺2

1)多线程调度:

每个对象都可以调用 Object 的 wait/notify 方法来实现等待/通知机制。

public class WaitNotifyDemo {public static void main(String[] args) {Object lock = new Object();new Thread(() -> {synchronized (lock) {System.out.println("线程1:我要等待");try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1:我被唤醒了");}}).start();new Thread(() -> {synchronized (lock) {System.out.println("线程2:我要唤醒");lock.notify();System.out.println("线程2:我已经唤醒了");}}).start();}
}

在大多数情况下,由于线程1先被启动,它会先获得锁。以下是详细的执行序列:

  1. 主线程启动:
    • •主线程创建了一个共享对象 lock作为监视器锁。
    • •主线程启动线程1。线程1进入 Runnable状态,等待CPU调度。
    • •主线程立即启动线程2。线程2也进入 Runnable状态。
  2. 线程1获得锁并进入等待:
    • •线程1获得CPU时间片,并成功获取 lock上的同步锁,进入 synchronized代码块。
    • •线程1打印:"线程1:我要等待"。
    • •线程1执行 lock.wait()。这个方法调用会导致以下关键操作:
      • •线程1释放其持有的 lock锁。
      • •线程1的状态由 RUNNABLE变为 WAITING,并被放入与 lock对象关联的等待队列中。
    • •此时,lock的锁被释放,其他线程可以竞争它。
  3. 线程2获得锁并发出通知:线程1被唤醒并继续执行:
    • •线程2获得CPU时间片,并成功获取到已空闲的 lock锁,进入其 synchronized代码块。
    • •线程2打印:"线程2:我要唤醒"。
    • •线程2执行 lock.notify()。这个方法调用会引发以下操作:
      • •JVM将线程1从 lock的等待队列移送到同步队列(或锁的阻塞队列)。线程1的状态由 WAITING变为 BLOCKED,因为它现在需要重新竞争锁才能继续执行。
      • •请注意:notify()调用本身并不会释放锁,线程2会继续持有锁并执行后续代码。
    • •线程2打印:"线程2:我已经唤醒了"。
    • •线程2执行到其 synchronized代码块的结束处 },这时它会释放​ lock锁。
    • •lock锁被释放后,在同步队列中等待的线程1开始尝试重新获取该锁。
    • •线程1成功获取锁后,从其 wait()方法处恢复执行。
    • •线程1打印:"线程1:我被唤醒了"。
    • •线程1执行到其 synchronized代码块的结束处 },释放锁。程序随后结束。
线程1:我要等待
线程2:我要唤醒
线程2:我已经唤醒了
线程1:我被唤醒了

潜在风险:竞态条件(Race Condition)

这段代码存在一个典型的竞态条件问题。如果线程调度器让线程2先于线程1执行,将会发生以下情况:

  1. 线程2先获得 lock锁。
  2. 线程2调用 lock.notify()。但此时,线程1尚未执行到 wait()方法,即等待队列是空的。因此,这次 notify()调用相当于一次空操作,没有任何线程会被唤醒。
  3. 线程2执行完毕,释放锁。
  4. 之后,线程1获得锁,执行 lock.wait()并进入等待状态。
  5. 由于已经没有任何其他线程会再次调用 lock.notify(),线程1将永远等待下去,程序无法正常终止。

 

2)Java包

Java 定义了一种名字空间,称之为包:package。一个类总是属于某个包,类名(比如Person)只是一个简写,真正的完整类名是包名.类名。

在 Java 虚拟机执行的时候,JVM 只看完整类名,因此,只要包名不同,类就不同。

要特别注意:包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。

 

在写import的时候,可以使用*,表示把这个包下面的所有class都导入进来(但不包括子包的class)。我们一般不推荐这种写法,因为在导入了多个包后,很难看出Arrays类属于哪个包。

 

还有一种import static的语法,它可以导入一个类的静态字段和静态方法。import static很少使用。

package main;// 导入System类的所有静态字段和静态方法:
import static java.lang.System.*;public class Main {public static void main(String[] args) {// 相当于调用System.out.println(…)out.println("Hello, world!");}
}

 

Java 编译器最终编译出的.class文件只使用 完整类名,因此,在代码中,当编译器遇到一个class名称时:

  • 如果是完整类名,就直接根据完整类名查找这个class;
  • 如果是简单类名,按下面的顺序依次查找:
    • 查找当前package是否存在这个class;
    • 查找import的包是否包含这个class;
    • 查找java.lang包是否包含这个class。

如果按照上面的规则还无法确定类名,则编译报错。

编写 class 的时候,编译器会自动帮我们做两个 import 动作:

  • 默认自动import当前package的其他class;
  • 默认自动import java.lang.*。

注意:自动导入的是java.lang包,但类似java.lang.reflect这些包仍需要手动导入。

如果有两个class名称相同,例如,mr.jun.Arrays和java.util.Arrays,那么只能import其中一个,另一个必须写完整类名。

相关新闻

  • Ai元人文:对岐金兰观察的深度回应——价值协商与数值优化的范式调和
  • 12/11
  • 深入解析:[特殊字符] 在 Windows 上设置 SQLite

最新新闻

  • 2026南宁名包回收性价比测评|同款包包,哪家到手价更高? - 薛定谔的梨花猫
  • 【无人机】基于球向量的粒子群优化SPSO算法在无人机路径规划中的实现附Matlab代码
  • 海牙认证如何办理?海牙认证多少钱一份?详细指南 - 指上通
  • 2026 年重庆永川区橱柜定制公司实测 TOP5 测评,家装业主选材避坑攻略 - LYL仔仔
  • 上海高端腕表回收,2026 年 6 月稀缺款溢价回收 - 讯息早知道
  • 2026太和装修售后“找不到人”?一位万达三号院业主的真心话:30年质保+30分钟响应,才是真靠谱的售后 - 装企自媒体训练营辉哥

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号