Java-线程同步(2)

Java-线程同步(1)说到Lock对象,但是和synchronized相比似乎只是多了一个tryLock和lockInterruptibly 功能?并不是这样,我们接着看Lock更加高大上的用法。

读锁与写锁

案例:有多个线程同时操作一个对象,这个对象有一个get方法和一个set方法。现在,我们期望的其实是:

  1. 如果没有线程调用set方法,那么我们希望所有的线程都可以get
  2. 如果有线程调用set方法,那么我们希望等待set结束后在调用get
  3. 我们set方法本身是同步的
    这种情况,我们可以用读写锁很好的解决。
PS: 事实上,读写锁有很多的概念以及很多的情况!
```java
 public void get() {
        mLock.readLock().lock();
        System.out.println("get(),线程:"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mLock.readLock().unlock();
    }

    public void set() {
        mLock.writeLock().lock();
        System.out.println("set(),线程:"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mLock.writeLock().unlock();
    }
1. 同时获取读锁情况
 final ThreadSync threadSync = new ThreadSync();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                threadSync.get();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                threadSync.get();
            }
        });
        thread1.start();
       try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();
image.png

可以看到,瞬间输出两句日志,说明它们互相之间没有加锁

2. 同时获取写锁情况
image.png

从时间上可以看出,两句日志相差1秒,正好是我延时的时间。所以说明它们互相之间加锁

3. 先获取写锁后获取读锁
image.png

这种情况下,也是无法获取到读锁的,因为有线程在写!

4. 先获取读锁后获取写锁
image.png

这个时间也相差一秒,也就是说:在读锁锁定的过程中,是不允许其他线程去写

5. 先获取读,在去请求写,最后在请求读

因为先获取到读锁之后,其他线程请求读锁可以直接获取。那么会不会出现一直无法获取到写锁的情况呢?
我通过四个线程去操作这个:

  • 第一个线程先获取读锁
  • 第二个线程去获取写锁
  • 最后两个线程去获取读锁


    image.png

    可以看到:第一个线程和第二个线程之间有延时。但是第三个和第四个线程并没有跨过第二个请求写锁的线程,而是等待第二个线程释放锁之后,才在获取读锁的。
    在读写锁中,其实有一个队列,就是为了防止这种一直无法调用到读锁或者写锁的情况。

// 获取锁队列的长度
mLock.getQueueLength()
image.png

可以看到:

  • 当第一个线程请求读锁后,由于直接过去到读锁,所以队列为0
  • 当第二、三、四线程都请求后,锁的数量也由0变为1,2,3
 thread1.start();
            Thread.sleep(100); //保证线程已经启动
System.out.println("锁队列长度:"+mLock.getQueueLength());
thread2.start();
            Thread.sleep(100);//保证线程已经启动
 System.out.println("锁队列长度:"+mLock.getQueueLength());
 thread3.start();
            Thread.sleep(100);//保证线程已经启动
 System.out.println("锁队列长度:"+mLock.getQueueLength());
  thread4.start();
            Thread.sleep(100);//保证线程已经启动
  System.out.println("锁队列长度:"+mLock.getQueueLength());

你可能感兴趣的:(Java-线程同步(2))