简介
Synchronized 关键字是 Java 中一种用于实现线程同步的机制。在多线程程序中,当多个线程同时访问共享资源时,可能会导致数据的不一致性和程序的错误行为。Synchronized 关键字可以解决这个问题,使得多个线程在访问共享资源时能够按照一定的顺序执行,从而保证程序的正确性。
作用
Synchronized 关键字可以用于两种情况:方法和代码块。在方法上使用 Synchronized 关键字可以保证方法的原子性,即在同一时刻只有一个线程可以执行该方法。在代码块上使用 Synchronized 关键字可以保证代码块的原子性,并且可以指定同步对象,即同步锁,来控制多个线程的访问顺序。
下面通过一个代码示例来说明 Synchronized 关键字的用法。
public class SynchronizedExample implements Runnable {
private int count = 0;
public synchronized void increment() {
count++;
}
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedExample synchronizedExample = new SynchronizedExample();
Thread t1 = new Thread(synchronizedExample);
Thread t2 = new Thread(synchronizedExample);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(synchronizedExample.count);
}
}
在这个示例中,我们定义了一个 SynchronizedExample 类,该类实现了 Runnable 接口。在 SynchronizedExample 类中,我们定义了一个私有属性 count 和一个公共方法 increment()。increment() 方法使用 synchronized 关键字修饰,以保证在同一时刻只有一个线程可以执行该方法。在 run() 方法中,我们循环调用 increment() 方法 10000 次来增加 count 的值。在 main() 方法中,我们创建了两个线程 t1 和 t2,并将它们都指向同一个 SynchronizedExample 实例。然后,我们启动这两个线程并等待它们的执行完成,最后输出 count 的值。
通过这个示例,我们可以看到 Synchronized 关键字的作用:保证了 increment() 方法的原子性,即在同一时刻只有一个线程可以执行该方法,从而保证了 count 的值的正确性。
除了在方法上使用 Synchronized 关键字外,我们还可以在代码块上使用 Synchronized 关键字来控制多个线程的访问顺序。在代码块上使用 Synchronized 关键字时,需要指定同步对象,即同步锁。同步锁可以是任意对象,但是需要保证多个线程使用的同步锁是同一个对象。下面是一个示例代码:
public class SynchronizedExample2 implements Runnable {
private final Object lock = new Object();
private int count = 0;
public void run() {
synchronized (lock) {
for (int i = 0; i < 10000; i++) {
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedExample2 synchronizedExample2 = new SynchronizedExample2();
Thread t1 = new Thread(synchronizedExample2);
Thread t2 = new Thread(synchronizedExample2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(synchronizedExample2.count);
}
}
在这个示例中,我们定义了一个 SynchronizedExample2 类,该类实现了 Runnable 接口。在 SynchronizedExample2 类中,我们定义了一个私有属性 lock 和一个公共方法 run()。在 run() 方法中,我们使用 synchronized 关键字修饰了一个代码块,并指定了同步锁为 lock。在代码块中,我们循环增加 count 的值。在 main() 方法中,我们创建了两个线程 t1 和 t2,并将它们都指向同一个 SynchronizedExample2 实例。然后,我们启动这两个线程并等待它们的执行完成,最后输出 count 的值。
通过这个示例,我们可以看到 Synchronized 关键字在代码块上的作用:使用同步锁来控制多个线程的访问顺序,从而保证 count 的值的正确性。
除了在 Java 中使用 Synchronized 关键字,还可以使用其他的线程同步机制,例如 Lock 和 Semaphore。Lock 是一个接口,提供了比 Synchronized 更灵活的线程同步机制,可以实现公平锁和非公平锁。Semaphore 是一个计数信号量,可以用来控制访问某个共享资源的线程数。
然而,在实际开发中,Synchronized 关键字仍然是最常用的线程同步机制之一。因为它简单易用,且可以自动释放锁,避免了死锁的发生。同时,Synchronized 关键字也是 JVM 内部实现的一种机制,具有较高的性能和可靠性。
在实际开发中,我们应该尽量减少对共享资源的访问,从而减少线程同步的需求。如果必须使用共享资源,应该尽量保证共享资源的不可变性,即共享资源的值不会被修改。另外,我们还可以使用线程安全的集合类,例如 ConcurrentHashMap 和 CopyOnWriteArrayList,来减少线程同步的需求。
总结
总之,Synchronized 关键字是 Java 中一种用于实现线程同步的机制。它可以保证方法和代码块的原子性,并且可以控制多个线程的访问顺序,从而保证程序的正确性。在实际开发中,我们应该尽量减少对共享资源的访问,并使用线程安全的集合类来减少线程同步的需求。