Synchronized
关键字是Java中用于同步代码块和方法的重要机制,主要用于在多线程并发执行时,防止线程之间的数据竞争和并发冲突,确保代码的安全执行。下面将详细介绍其作用、使用方法和示例说明。
作用
Java的多线程并发执行时,会出现多个线程同时访问共享数据的情况,这种情况下可能会出现各种竞态条件和并发问题,导致程序出错,例如线程间的冲突、死锁、数据不一致等,而synchronized
关键字就是用来解决这些问题,其作用主要有以下几点:
- 保护临界区共享资源:比如多个线程并发访问同一个对象时,使用
synchronized
关键字可以确保在同一时间只有一个线程可以进入临界区执行代码,其他线程需要等待当前线程执行完毕才能进行访问,从而解决冲突问题。 - 确保可见性和有序性:使用
synchronized
关键字可以确保线程间对共享变量的操作是有序的,一个线程对共享变量的修改对其他线程是可见的,并且不会被重新排序。 - 提高程序的性能:虽然
synchronized
关键字会在多个线程访问共享资源时引起一定的开销,但是使用它却可以避免同步问题,确保代码的正确性,进而提高程序的性能。
使用方法
synchronized
关键字可以用于修饰方法或代码块,其语法如下:
// 修饰方法
public synchronized void method() {
//...
}
// 修饰代码块
synchronized (lockObject) {
//...
}
其中,method()
方法是一个同步方法,在多个线程同时调用该方法时,只有一个线程可以进入执行,其他线程需要等待;lockObject
是一个对象锁,可以在代码块中使用synchronized
关键字来保护临界区代码的安全执行。
示例说明
下面给出两个使用synchronized
关键字的例子,以说明其作用及使用方法:
- 使用
synchronized
修饰方法,确保线程安全。
public class Counter {
private int count;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public int getCount() {
return count;
}
}
// 使用示例
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.decrement();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count: " + counter.getCount()); // 输出 0
在这个例子中,Counter
类中的increment()
和decrement()
方法都被使用synchronized
关键字进行修饰,这意味着在同一时间,只有一个线程能够执行其中的一个方法。这样可以确保线程安全,避免出现并发问题。
- 使用
synchronized
修饰代码块,让多个线程按照一定的顺序轮流打印数字。
public class PrintNumber {
private static final Object lock = new Object();
private static int number = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
while (number < 100) {
synchronized (lock) {
if (number % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
}
}
}
});
Thread t2 = new Thread(() -> {
while (number < 100) {
synchronized (lock) {
if (number % 2 != 0) {
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
}
}
}
});
t1.start();
t2.start();
}
}
// 输出结果随机
// Thread-1: 0
// Thread-0: 1
// Thread-1: 2
// Thread-0: 3
// Thread-1: 4
// Thread-0: 5
// ...
在这个例子中,PrintNumber
类中的main()
方法包含了两个线程t1
和t2
,它们会轮流打印数字。使用synchronized
关键字来修饰代码块,确保这些线程按照一定的顺序调用,从而保证了线程之间的正确性。