synchronized关键字的作用是什么?

  • Post category:Java

Synchronized关键字是Java中用于同步代码块和方法的重要机制,主要用于在多线程并发执行时,防止线程之间的数据竞争和并发冲突,确保代码的安全执行。下面将详细介绍其作用、使用方法和示例说明。

作用

Java的多线程并发执行时,会出现多个线程同时访问共享数据的情况,这种情况下可能会出现各种竞态条件和并发问题,导致程序出错,例如线程间的冲突、死锁、数据不一致等,而synchronized关键字就是用来解决这些问题,其作用主要有以下几点:

  1. 保护临界区共享资源:比如多个线程并发访问同一个对象时,使用synchronized关键字可以确保在同一时间只有一个线程可以进入临界区执行代码,其他线程需要等待当前线程执行完毕才能进行访问,从而解决冲突问题。
  2. 确保可见性和有序性:使用synchronized关键字可以确保线程间对共享变量的操作是有序的,一个线程对共享变量的修改对其他线程是可见的,并且不会被重新排序。
  3. 提高程序的性能:虽然synchronized关键字会在多个线程访问共享资源时引起一定的开销,但是使用它却可以避免同步问题,确保代码的正确性,进而提高程序的性能。

使用方法

synchronized关键字可以用于修饰方法或代码块,其语法如下:

// 修饰方法
public synchronized void method() {
    //...
}

// 修饰代码块
synchronized (lockObject) {
    //...
}

其中,method()方法是一个同步方法,在多个线程同时调用该方法时,只有一个线程可以进入执行,其他线程需要等待;lockObject是一个对象锁,可以在代码块中使用synchronized关键字来保护临界区代码的安全执行。

示例说明

下面给出两个使用synchronized关键字的例子,以说明其作用及使用方法:

  1. 使用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关键字进行修饰,这意味着在同一时间,只有一个线程能够执行其中的一个方法。这样可以确保线程安全,避免出现并发问题。

  1. 使用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()方法包含了两个线程t1t2,它们会轮流打印数字。使用synchronized关键字来修饰代码块,确保这些线程按照一定的顺序调用,从而保证了线程之间的正确性。