Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿

 目录

前言

多线程开发中,同步控制是必不可少的手段。而同步的实现需要用到锁,Java中提供了两种基本的锁,分别是synchronized 和 Lock。两种锁都非常常用,但也各有利弊,下面开始学习。

synchronized用法

synchronized 是Java的关键字,是应用最为广泛的同步工具之一。当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,同时,值得说明的是,它是在软件层面依赖JVM实现同步的。

synchronized 的用法很简单,直接用其修饰代码块即可,一般可将其用于修饰方法和代码块,根据修饰地方的不同还有不同的作用域,下面一一介绍。

修饰方法

synchronized 修饰方法分为两种情况:

  • 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。
  • 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。

修饰实例方法

顾名思义就是修饰类中的实例方法,并且默认是当前对象作为锁的对象,而一个对象只有一把锁,所以同一时刻只能有一个线程执行被同步的方法,等到线程执行完方法后,其他线程才能继续执行被同步的方法。实例代码如下:

public class SyncTest implements Runnable{      //静态变量     public static int TEST_INT = 0;      //被同步的实例方法     public synchronized void increase(){         TEST_INT++;     }      @Override     public void run() {         for(int i=1;i<=100000;i++){             increase();         }     }      public static void main(String[] args) throws InterruptedException {         //实例化对象         SyncTest instance = new SyncTest();         Thread t1=new Thread(instance);         Thread t2=new Thread(instance);         t1.start();         t2.start();         t1.join();         t2.join();         System.out.println(TEST_INT);     } }

运行上方的程序,结果会是200000,因为main函数中只实例化一个SyncTest对象,所以,两个线程运行的时候只能有一个线程获取到对象的锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,所以无法访问该对象的其他synchronized实例方法,当然其他线程还是可以访问该对象的非synchronized方法的。

不过,上面的情况只是针对一个对象实例进行操作,如果有多个对象实例的话,修饰实例方法是无法保证线程安全的,我们可以把main函数的程序修改下:

public static void main(String[] args) throws InterruptedException {     //每个线程实例化一个SyncTest对象     Thread t1=new Thread(new SyncTest());     Thread t2=new Thread(new SyncTest());     t1.start();     t2.start();     t1.join();     t2.join();     System.out.println(TEST_INT); }

运行程序后,会发现结果永远小于200000,说明synchronized没有起到同步的作用了,说明修饰实例方法只能作用实例对象,不能作用到类对象。

修饰静态方法

要想synchronized同步到类对象本身,可以用它修饰类中的静态方法。修改下上述代码中的increase方法为静态方法,并在main函数中新建两条线程:


                    
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信