八股:什么是java间的线程同步?

24 阅读3分钟

问:什么是java间的线程同步

答:

是什么?:是一种机制,一种在多线程环境下,确保同一时刻,只有一个线程可以执行共享资源的临界区代码 为什么?:因为在多线程环境下,多个线程同时对共享资源进行访问或写入的操作,可能会导致数据不一致、静态条件、死锁等问题的产生 怎么做?:通过加锁的方式,来实现临界区的代码在同一时刻只能被一个线程执行 具体实现:

1.synchronized关键字,通过在方法或者代码块上添加synchronized关键字,实现同步机制 2.通过ReenTrantLock类的lock()和unlock()方法实现 3.通过原子类实现,Java中的Atomic类提供了一系列的原子类,例如:AtomicInteger、AtomicLong、AtomicRefrence等,通过这些原子类,可以实现在不使用java代码加锁的形式实现同步机制,原理是这些原子类通过硬件级别的原子操作来实现操作的原子性。

本题相关知识点(以下内容为笔者在学习本题时不清楚的知识点,上述解答在阅读时,如没有疑问,下述知识点可直接跳过):

共享资源: 在多线程或者分布式系统中,多个线程、进程、组件都可以执行访问或者写入的操作的资源,常见的共享资源是数据或者对象,比如:实例变量、静态变量、集合等 静态条件: 当多个线程竞争同一个资源的时候,线程的输出或者行为,取决于线程被CPU调度的时机,而不是程序本身的逻辑 临界区: 是一段代码,这段代码里写的是,在多线程环境下,对共享资源进行访问或写入的代码逻辑

synchronized实现同步机制:

1.synchronized加在实例方法上,锁住的对象是调用方法的实例对象 2.synchronized加在静态方法上,锁住的是类对象 3.synchronized加在代码块上,可以指定一个特定的对象作为锁,此方法更加灵活 4.

public class Counter {
    private int count = 0;

    // 同步实例方法
    public synchronized void increment() {
        count++;
    }

    // 同步静态方法
    public static synchronized void staticIncrement() {
        // 静态方法的锁是类的 Class 对象
    }
}


public class Counter {
// 创建锁对象
    private final Object lock = new Object();
    private int count = 0;

    public void increment() {
    // 加在代码块上,指定特定对象为锁
        synchronized (lock) {
            count++;
        }
    }
}

ReenTrantLock实现同步机制:

ReenTrantLock是java的JUC中包下的一个类,提供了lock()方法加锁和unlock方法解锁,相比于synchronized来说更加的灵活,因为它允许手动添加或者释放锁,而syunchronized不允许手动释放,并且它支持公平锁、非公平锁、条件变量等功能。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock();  // 获取锁
        try {
            count++;
        } finally {
            lock.unlock();  // 释放锁
        }
    }
}

原子类实现同步机制实例:

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet();  // 原子操作
    }

    public int getCount() {
        return count.get();
    }
}