[Java]synchronized、Lock以及volatile

一、线程

线程就是一个轻量级的线程,进程执行时真正完成任务的是线程。它跟进程一样拥有独立的运行控制,只是线程没有独立的存储空间,而是和进程中其他线程共享存储空间。

二、临界资源访问

临界资源就是同一时刻只允许一个线程访问的资源,我们通过一个代码来解释:

public class Test05 {
    int i = 0;
    public void plusI(){
        i++;
    }
    
    public int getI(){
        return i;
    }
}

代码中,i就是我们说的临界资源,plusI和getI就是临界区。如果多个线程去执行的话可能会导致i的结果不如你想象,比如有个线程t1去进行plusI操作,还未执行完i++的时候有个t2去进行getI操作,造成数据不一致。

这时候我们就要用上标题上的几个关键字了。

1、synchronized

为了保证操作的完整性,Java引入了互斥锁的概念,Java中每个对象都有一个互斥锁,同一时刻只有一个线程能够访问临界区。synchronized关键字用来给对象加锁,它可以修饰方法或代码块,成为同步方法或同步代码块。

synchronized代码块的使用如下:

synchronized(对象){
//访问临界资源的代码
}

synchronized块中的代码拿到锁后,直到执行完块中的代码,才会释放锁,保证了其他线程不会同时操作这个对象,确保数据一致。当然synchronized修饰的方法也有同样的效果,修饰方法同步的对象是this,跟修饰代码块效果是一样的。

2、Lock

Lock是一个类(接口),可以自己加锁和释放锁。有几个主要的方法:

void lock():如果锁处于空闲,获取到锁,否则等待到锁之后才执行当前线程。

boolean tryLock():与lock不同的是它只是尝试获取锁,锁不可用也还会执行当前进程代码。

void unlock():释放锁。

ReentrantLock实现了Lock,是一个可重入(可再次获取到该对象的锁)的互斥锁。

Lock lock = new ReentrantLock();
lock.lock();
i++;
lock.unlock();

3、volatile

Java提供了volatile关键字来保证可见性,当一个用volatile修饰的变量改变时它的值会立即更新到主存,而普通的变量什么时候写入主存是不一定的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注