Java锁相关总结

1.ReentrantLock对象
private ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
     //代码段
}
finally {
     lock.unlock();  // 这步至关重要,千万不能遗漏
}

a.一旦一个线程获得了锁对象,那么其他线程都将阻塞在lock.lock()方法中;

b.锁对象是可重入的(即已经获得锁的线程可以再次获得锁),这时候琐计数+1,当线程调用unlock方法时,琐计数-1,只有当琐计数为0时,才被释放;

c.ReentrantLock类还具有一个带有boolean参数的构造方法,该参数表示是否需要执行公平策略,一个公平锁偏爱等待时间最长的线程(会降低性能),默认是随机选择一个线程获得锁;

2.基于锁的条件变量

a.如何创建一个条件变量?
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();

b.如何使用条件变量?
当一个线程获得锁后,发现不具备执行下一步条件时,这时候可以调用condition.await()方法,该方法会导致当前线程释放锁,并且阻塞在当前条件的等待集中;只有当另一个线程调用condition.signalAll()方法或是condition.signal()方法,才能解除阻塞(线程会去重新竞争锁,当再次获得锁后便从await方法返回);

通过条件变量,我们可以简单的实现一个生产者消费者模型(java sdk中代码):
class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newC ondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)  // 一定要是while循环
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }


c.signal()方法和singalAll()方法的区别:
signalAll方法激活因为该条件而等待的所有线程,而singal只激活其中一个线程;

3.synchronized关键字
a.java中每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么整个方法将被保护起来:
void synchronized method() {
     // 代码片段
}

等价于
void method {
     this.inner.lock(); 
     try {
          // 代码片段
     } finally {
          this.inner.unlock();
     }
}

b.内部对象锁只有一个条件变量,我们可以通过wait方法将线程放入等待集中,也可以通过notif/notifAll方法唤醒等待集中的线程;

c.在静态方法前加synchronized,这时候获得的锁不是对象的内部锁(因为这时候还没对象),获得是当前类字节码锁,所以
public static synchronized void method1 {
}

public static synchronized void method2 {
}

public synchronized void method3 {
}

public synchronized void method4 {
}

method1和method2线程同步,method3和method4线程同步,其余方法之间没有线程同步






你可能感兴趣的:(java)