synchronized 修饰符
1.方法级别的 synchronized
:
使用synchronized
修饰方法,可以确保同一时间只有一个线程能够执行这个方法。这是最简单的同步方式、
public synchronized void synchronizedMethod() {
// 这个方法是同步的
// 在方法内的操作是线程安全的
}
2.代码块级别的 synchronized
:
使用synchronized
块,可以指定一个对象(通常是一个共享的锁对象),以确保只有一个线程能够执行包含在 synchronized
块内的代码。它使用了 lockObject
作为锁对象。在进入同步块之前,线程会尝试获取 lockObject
上的锁。如果锁已经被另一个线程占用,那么线程将被阻塞,直到锁被释放。
Object lockObject = new Object(); // 通常用作锁对象
synchronized (lockObject) {
// 这里的代码是同步的
// 在代码块内的操作是线程安全的
}
3.实例级别的 synchronized
:
当多个线程需要同步访问同一个对象的实例方法时,可以使用实例级别的 synchronized
。这意味着同一对象的不同方法不能被不同线程同时调用(即标记在类中的函数上而不是类上)
class MyObject {
public synchronized void synchronizedMethod1() {
// 这个方法是同步的,只有一个线程能够执行
// 另一个线程无法同时调用 synchronizedMethod2
}
public synchronized void synchronizedMethod2() {
// 这个方法也是同步的
}
public void nonSynchronizedMethod() {
// 这个方法不是同步的,多个线程可以同时调用
}
}
4.静态方法的 synchronized
:
当多个线程需要同步访问同一个类的静态方法时,可以使用静态方法级别的 synchronized
。这会锁定整个类而不是实例。(因为这个标记不能标记在类上,只能在静态函数上实现这个效果)
public static synchronized void staticSynchronizedMethod() {
// 这个静态方法是同步的
}
5.等待-通知机制的 synchronized
:
synchronized
还用于实现等待-通知机制,允许一个线程等待另一个线程完成某项操作。这通常用于线程间协作的情况,例如生产者-消费者问题。
// 在生产者线程中
synchronized (sharedQueue) {
// 生产数据
sharedQueue.notify(); // 通知等待的消费者线程
}
// 在消费者线程中
synchronized (sharedQueue) {
while (sharedQueue.isEmpty()) {
sharedQueue.wait(); // 等待生产者通知
}
// 消费数据
}
transient 修饰符
序列化的对象包含被 transient
修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
它的主要作用是告诉 Java 序列化机制,在将对象持久化(通常是将对象写入文件或通过网络传输)时,应该忽略带有 transient
修饰符的字段。这意味着这些字段的值不会被保存,也不会被传输。transient
的主要用途包括以下情况:
-
安全性:有些字段包含敏感信息,如密码、密钥等,不应该被序列化到外部存储或传输到其他系统。通过将这些字段标记为
transient
,可以确保它们在序列化过程中被忽略。 -
临时数据:有些字段是暂时性的,不需要持久化。例如,您可能有一个用于缓存计算结果的字段,但这些缓存值不应该被序列化,因为它们可以在反序列化后重新生成。
-
不可序列化的字段:有些字段的类型不支持序列化,或者是第三方库的类,不能被序列化。通过将这些字段标记为
transient
,可以确保整个对象可以被序列化,而不必考虑这些无法序列化的字段。
volatile 修饰符
volatile
修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个 volatile
对象引用可能是 null
。
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run()
方法(在 Runnable
开启的线程),在另一个线程调用 stop()
方法。 如果 第一行 中缓冲区的 active
值被使用,那么在 第二行 的 active
值为 false
时循环不会停止。
但是以上代码中我们使用了 volatile
修饰 active
,所以该循环会停止。