synchronized关键字如何保证线程安全?

  • Post category:Java

当多个线程访问共享数据时,如果没有有效的同步机制,将会导致数据出现意想不到的错误。Java提供了synchronized关键字,这是Java中最基本的同步机制。它保证在同一时间,只有一个线程可以访问对象的代码块或方法。这样可以避免多个线程同时执行同一个代码块或方法导致数据不一致的问题。

synchronized关键字可以用于修饰代码块或方法。使用synchronized修饰的代码块或方法,都称之为同步代码块或同步方法。在同步代码块或同步方法中,只有获取锁的线程才有访问数据的权限,其他线程必须等待获取锁的线程执行完之后才能访问数据。

下面是两条使用示例:

示例一:使用synchronized修饰方法
public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

上面的代码中,increment()getCount()方法都被修饰为synchronized方法。这样,在increment()方法执行期间,其他线程无法访问该方法或getCount()方法。只能等待increment()方法执行完之后才可以访问getCount()方法。

示例二:使用synchronized修饰代码块
public class SynchroTest implements Runnable {
    private static int count;

    private static final Object LOCK = new Object();

    @Override
    public void run() {
        synchronized (LOCK) {
            for (int i = 0; i < 100000; i++) {
                count++;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SynchroTest test = new SynchroTest();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }
}

上面的代码中,使用synchronized修饰了一个代码块,该代码块使用了一个对象锁。两个线程Thread t1Thread t2获取的都是同一个对象锁。虽然它们执行的是同一个代码块,但是由于获取同一个锁进行顺序访问,保证了线程安全,最后输出的count的值是200000。

如果不使用synchronized进行同步,则两个线程的执行顺序是随机的,就不能保证线程安全了。