Java synchronized 用法
在多线程编程中,我们经常需要处理共享资源的访问问题。Java提供了synchronized关键字来实现线程的同步,以确保多个线程对共享资源的安全访问。本文将介绍Java synchronized关键字的用法,并通过代码示例来说明其具体应用。
1. synchronized关键字的基本用法
在Java中,synchronized关键字可以用于方法或代码块上。使用synchronized修饰的方法或代码块称为同步方法或同步代码块。它可以保证同一时刻只有一个线程能够执行被synchronized修饰的代码,从而避免了多线程访问共享资源时可能出现的数据不一致或竞态条件等问题。
1.1 同步方法
使用synchronized修饰方法,可以将整个方法声明为同步方法。当一个线程进入同步方法时,它会自动获取该方法所属对象的锁,并在执行完方法后释放锁,让其他线程可以继续进入。
代码示例:
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
}
1.2 同步代码块
除了同步方法,我们还可以使用synchronized修饰代码块。同步代码块使用一个对象作为锁,只有获取了该对象的锁的线程才能执行代码块中的内容。
代码示例:
public class SynchronizedExample {
private int count = 0;
private Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
}
2. synchronized关键字的使用场景
synchronized关键字的主要作用是保护共享资源,防止多线程并发访问时出现数据不一致的问题。下面通过几个场景来说明synchronized关键字的使用。
2.1 多线程访问共享变量
当多个线程同时访问共享变量时,如果没有进行同步控制,可能会出现数据竞争的问题。在这种情况下,我们可以使用synchronized关键字来保证同一时刻只有一个线程能够修改共享变量。
代码示例:
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
}
2.2 线程安全的集合类
Java提供了一些线程安全的集合类,如Vector和Hashtable。这些集合类内部使用synchronized关键字来保证多线程并发访问时的线程安全性。
代码示例:
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
vector.add(3);
2.3 线程间的通信
synchronized关键字还可以用于线程间的通信,通过wait、notify和notifyAll方法来实现线程的等待和唤醒。
代码示例:
public class SynchronizedExample {
private boolean flag = false;
public synchronized void waitForFlag() throws InterruptedException {
while (!flag) {
wait();
}
}
public synchronized void setFlag() {
flag = true;
notifyAll();
}
}
3. synchronized关键字的局限性
尽管synchronized关键字可以确保线程安全,但它也存在一些局限性。
3.1 细粒度锁
使用synchronized关键字时,锁的粒度较大,会导致其他线程无法并发执行访问其他非共享资源的代码。为了避免这个问题,可以考虑使用细粒度锁,即使用多个锁来控制不同的资源。
3.2 性能问题
synchronized关键字会引入一定的性能开销。在高并发场景下,如果同步代码块的执行时间较长,会导致其他线程长时间等待锁的释放,从而降低系统性能。为了提高并发性能,可以使用更轻量级的锁,如ReentrantLock。