synchronized关键字是Java中用于实现线程同步的关键字。它可以修饰方法或代码块,用于保证在同一时间只有一个线程可以访问被synchronized修饰的方法或代码块。
当一个线程进入synchronized修饰的方法或代码块时,它将获得对象的锁。其他线程必须等待锁的释放才能进入同步块。一旦线程执行完同步块中的代码,它将释放锁,允许其他线程进入。
除了synchronized关键字外,还有其他方式可以实现线程安全。以下是一些常用的方式:
- 使用Lock接口和它的实现类(如ReentrantLock):Lock接口提供了更灵活和可扩展的方式来实现线程同步。它提供了更多的功能,如可重入锁、公平锁和条件变量等。
- 使用Atomic类:Java.util.concurrent.atomic包中提供了一系列的原子类,如AtomicInteger、AtomicLong等。这些类使用原子操作来保证对变量的读写操作是线程安全的。
- 使用volatile关键字:volatile关键字用于修饰变量,对于被volatile修饰的变量,线程每次读取该变量时都会从主内存中读取,而不是从线程的本地缓存中读取。这可以保证变量的可见性,但不保证原子性。
- 使用线程安全的集合类:Java.util.concurrent包提供了线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList等。这些类在进行读写操作时都会采用一定的机制来保证线程安全。
- 使用synchronized关键字和wait、notify、notifyAll方法:这些方法用于实现线程之间的通信和协作。可以通过synchronized关键字的配合来实现线程的等待和唤醒。
需要根据具体的场景和需求选择合适的方式来实现线程安全。
下面是一个使用synchronized关键字实现线程同步的示例代码:
public class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
example.increment();
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
example.increment();
}
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + example.count);
}
}
在上面的示例中,我们创建了一个SynchronizedExample
类,该类有一个count
成员变量和一个increment()
方法。在increment()
方法上使用了synchronized
关键字,这使得该方法在同一时间只能由一个线程访问。
我们创建了两个线程thread1
和thread2
,它们都会调用increment()
方法来递增count
变量的值。因为increment()
方法是同步的,所以在同一时间只有一个线程能够访问该方法,从而保证了线程安全。
最后,我们使用thread1.join()
和thread2.join()
方法来等待线程执行完毕,并打印出count
的最终值。