锁:synchronized和ReentrantLock两种机制都可以用来保证同一时刻只有一个线程访问临界区中的资源。
- Synchronized
Synchronized关键字可以作为方法的修饰符,如果一个静态方法被synchronized关键字修饰,那么当一个线程调用该方法时,其他的线程将不能调用该类的其他的由synchronized关键字修饰的静态方法(但是可以调用由synchronized修饰的非静态方法),即锁住了类对象。
如果一个实例方法被synchronized关键字修饰,那么当一个线程调用该方法时,其他的线程将不能调用该对象的其他的由synchronized关键字修饰的方法(但是可以调用由synchronized修饰的静态方法),即锁住了实例对象。
- ReentrantLock
ReentrantLock:创建 ReentrantLock lock = new ReentrantLock(); 启动:lock.lock(); 解除:lock.unlock() 解除的代码最好放在finally块中,避免发生异常时,锁也会被释放。
- 条件对象
通常线程进入临界区,却发现在满足某一条件之后它才能运行。要使用一个条件对象来管理那些已经或得了一个锁但是却不能执行的线程。条件对象伴随着锁而生。
创建 Condition con = lock.newCondition();
使用:con.await(); 阻塞当前线程,并放弃锁。进入该Condition对象的等待集。当一个线程调用await后它没有办法重新激活自身。如果没有线程来激活它,它就永远不再运行了。
con.signalAll();激活因为这一Condition对象等待的所有线程。并将这些线程从该Condition对象的等待集中移除,它们再次成为可运行的,调度器将再次激活它们。同时,它们将试图重新进入临界区,一旦锁成为可用的,它们中的某个将从await调用返回,获得锁并从被阻塞的地方继续运行。signalAll不会立即激活一个等待线程。它仅仅解除等待线程的阻塞,以便这些线程可以在当前线程退出同步方法后,通过竞争实现对象的访问。
- 相似方法
wait()和notify()必须在synchronized的代码块中使用 因为只有在获取当前对象的锁时才能进行这两个操作 否则会报异常 而await()和signal()一般与Lock()配合使用