网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 后端开发 > Java >

java研发工程师必知必会

时间:2026-01-23 22:08

人气:

作者:admin

标签:

导读:java作为一种跨平台、面向对象的编程语言,广泛应用于企业级Web开发和移动应用开发。其核心特性包括可移植性(一次编写,到处运行)、安全性、分布式支持以及泛型编程能力。又因...

java作为一种跨平台、面向对象的编程语言,广泛应用于企业级Web开发和移动应用开发。其核心特性包括可移植性(一次编写,到处运行)、安全性、分布式支持以及泛型编程能力。又因其简单易学深受广大程序员所喜爱。自1995年推出以来,语言也经历了多次的迭代更新,而对于一些较早接触该语言的老程序员来说,对一些新特征甚至语言层面的优化或许并不熟悉,针对一些较为常见的语言特征,在本文中进行了较为细致的入门介绍,希望能在学习语言的过程中起到积极的作用。另外由于水平有限,对某些特性的理解或许存在偏差,如果您发现有任何问题,欢迎随时交流学习。
1、volatile在线程安全中能保证什么

通常以为,使用volatile变量就可以保证线程安全.事实真的如此吗?
其实,volatile只能保障的是可见性和排序,并不能保证操作的原子性,更不能防止竞态条件(race conditions)的发生.当一个变量被标记为volatile时,1) 某线程对该变量的任何写入操作会立即对其他线程可见;2) 读写操作不会对该变量的相关操作进行重排序.

volatile int i;
i++;

代码中变量i虽然使用volatile修饰,但其并不是线程安全的,因为i++不是一个原子操作,它包含1 读取数值;2 加1;3 写回数值.因volatile修饰变量不能保证原子性,当两个线程同时执行上述代码,便会导致线程安全的问题.
2、是否应该选择synchronized锁
长久以来的认知告诉我们,synchronized速度慢,要避免使用.选用替代方案concurrent.lock包下的作为替代方案.从jdk1.6开始,针对synchronized的优化已经显著提高了其性能,jdk1.6引入了”锁升级”机制, 将锁的状态分为四种:‌无锁 → 偏向锁 → 轻量级锁 → 重量级锁‌。JVM 会根据线程竞争情况动态升级锁,避免不必要的开销.
许多情况下, synchronized由JVM优化,比手动锁定更快,语义也更容易理解.但当多个线程争用一个synchronized锁时,速度会变慢.如下代码中,如果doSomeThing()抛出异常,会发生什么情况?

synchronized (lock) {
doSomeThing();
}

锁会自动释放!
同样如果使用手动锁,则必须注意锁释放.如使用ReentrantLock,需注意解锁某个finally区域,否则,一旦异常该区域将永远保持锁定状态,出现死锁.

lock.lock ();
try {
    doSomeThing ();
} finally {
    lock.unlock () ;
}

3、可以使用Thread.sleep()协调线程吗

答案是否定的.因为Thread.sleep()并不能保证时间,不能协调状态,会在机器低速运转或重载时发生故障.想要正确的协调线程,需使用:
1、wait()/notify();
2、CountDownLatch;
3、CyclicBarrier;
4、CompletebleFuture.
那么,wait()和sleep()之间有什么区别呢?
其区别主要包括
1、sleep()不释放锁,线程将占用cpu资源,wait()会释放监视器锁,
2、sleep()可以在任何地方使用,而wait()必须在synchronized代码块/方法中使用
3、sleep()作用是暂停执行(休眠),而wait()作用是线程间通信
4、sleep()的唤醒条件是超时自动唤醒,而wait()需等待notify()或notifyAll()
用一个日常生活中的场景大致描述一下,sleep()类似于你在床上看书,看累了抱着书躺下睡觉,虽然你不再看书,但因为书被你抱着,其他人是没法去看你手中的书.wait()类似你去排队出地铁站,在出站前你发现手机支付地铁票有问题,于是你让出排队通道去修复地铁卡手机支付,其他人依次跟上排队出站,等你解决了支付问题,又重新排进了出站队伍中.
在系统中,特别是多线程系统中使用sleep()只会降低系统性能.
4、多线程环境中,双重检查一定是安全的吗?

以下代码,在多线程环境中,是否存在问题?

public class MyClass {
    private static MyClass instance;
    public static MyClass getInstance() {
        if (instance == null) {
            synchronized (MyClass.class) {
                if (instance == null) {
                    instance = new MyClass();
                }
            }
        }
        return instance;
    }
} 

  答案是肯定的。问题的根本是因为指令重排的存在,而JVM在执行instance = new MyClass();这行代码时,其操作并不是原子的,通常分为三个步骤: •

• 1.分配内存空间:为对象分配一块内存。
• 2.初始化对象:在内存中构造对象(执行构造函数)。
• 3.引用赋值:将 instance 变量指向刚才分配的内存地址。
而JVM和CPU为了优化性能,这三个步骤并不是严格的顺序执行的.这便可能导致另一个线程可能会看到一个半初始化的对象.而修复此问题便可以通过使用添加volatile修饰禁止其重排序修复后代码如下

public class MyClass {
	// 必须增加 volatile 关键字
	private static volatile MyClass instance;

	public static MyClass getInstance() {
		if (instance == null) {
			synchronized (MyClass.class) {
		if (instance == null) {
			instance = new MyClass();
		}
		}
		}
		return instance;
	}
}

5、Java对象创建经历哪些阶段?

Java对象创建的五个阶段——类加载检查、内存分配、零值初始化、对象头设置和执行<init>方法——在逻辑上是顺序执行的。这些步骤共同构成了Java虚拟机(JVM)实例化对象的过程,按照由前到后的顺序保证了对象在内存中的正确配置和初始化。
具体细节如下:
• 1. 类加载检查:虚拟机检查new指令的参数能否在常量池中定位到一个类的符号引用,并检查该类是否已加载、解析和初始化。
• 2. 内存分配:在类加载检查通过后,虚拟机为对象在堆中分配内存。
• 3. 零值初始化:将分配的内存空间初始化为零值(不包含对象头),保证字段在该阶段就能使用默认值。
• 4. 对象头设置:设置对象头,包括哈希码、GC分代年龄、锁状态标志等。
• 5. 执行<init>方法:执行开发者定义的构造函数,按照程序员的意愿对对象进行初始化。

 
温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信