synchronized关键字可以实现线程之间的同步互斥给工作,Lock对象锁是一种完成同步互斥工作更优秀的机制,在1.6之后,对synchronized进行了优化,虽然效率上有所提升,但是在灵活度上仍然不如Lock对象。比如嗅探锁定,夺路分支等功能。
在需要同步的代码部分添加锁定,但是最后一定不要忘记了释放锁,否则会造成锁无法释放,其他线程不能执行。
package com.company.lockTest;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by BaiTianShi on 2018/8/23.
*/
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();
private void method1(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method1中结束运行");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method2(){
;
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method2中结束运行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest r = new ReentrantLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
r.method1();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
r.method2();
}
}, "t2");
t1.start();
t2.start();
}
}
执行结果:
t1在method1中开始运行
t1在method1中结束运行
t2在method2中开始运行
t2在method2中结束运行
在使用synchronized的时候,如果需要多线程间进行协调工作,则需要Object的wait()和notify()、notifyAll()方法配合使用。在使用Lcok对象锁的时候,可以使用一个新的等待通知类,他就是condition。这个Condition一定是针对某把锁的,也就是说只有在锁的基础上才能使用condition。
package com.company.lockTest;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by BaiTianShi on 2018/8/23.
*/
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private void method1(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method1将执行等待方法");
condition.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method1跳出等待,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method2(){
;
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method2中结束运行并通知等待线程");
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest r = new ReentrantLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
r.method1();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
r.method2();
}
}, "t2");
t1.start();
t2.start();
}
}
运行结果:
t1在method1中开始运行
t1在method1将执行等待方法
t2在method2中开始运行
t2在method2中结束运行并通知等待线程
t1在method1跳出等待,继续执行
一个Lock可以创建多个condition进行多线程间的交互,非常的灵活,可以使得部分需要唤醒的线程唤醒,其他线程继续等待通知。
package com.company.lockTest;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by BaiTianShi on 2018/8/23.
*/
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private void method1(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method1中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method1将执行condition1的等待方法");
condition1.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method1跳出condition1的等待,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method2(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method2中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method2将执行condition1的等待方法");
condition1.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method2跳出condition1的等待,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method3(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method3中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method3将执行condition2的等待方法");
condition2.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method3跳出condition2的等待,继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method4(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method4中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method4通知因condition1等待的线程");
condition1.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
private void method5(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"在method5中开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"在method5通知因condition2等待的线程");
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest r = new ReentrantLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
r.method1();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
r.method2();
}
}, "t2");
Thread t3= new Thread(new Runnable() {
@Override
public void run() {
r.method3();
}
}, "t3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
r.method4();
}
}, "t4");
Thread t5 = new Thread(new Runnable() {
@Override
public void run() {
r.method5();
}
}, "t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
执行结果
t2在method2中开始运行
t2在method2将执行condition1的等待方法
t3在method3中开始运行
t3在method3将执行condition2的等待方法
t1在method1中开始运行
t1在method1将执行condition1的等待方法
t4在method4中开始运行
t4在method4通知因condition1等待的线程
t5在method5中开始运行
t5在method5通知因condition2等待的线程
t2在method2跳出condition1的等待,继续执行
t1在method1跳出condition1的等待,继续执行
t3在method3跳出condition2的等待,继续执行
读写锁ReentrantReadWriteLock,其核心就是实现读写分离的锁,在高并发的情况下,尤其是读多写少时,性能要远高于ReentrantLock。不同于synchronized和ReentrantLock,同一时间,只能有一个线程访问被锁的代码。读写锁其本质是分成两个锁,即读锁和写锁。在读锁下,多个线程可以并发访问,在写的时候,只能一个一个顺序访问。遵循口诀:读读共享、写写互斥、读写互斥。
package com.company.lockTest;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Created by BaiTianShi on 2018/8/23.
*/
public class ReentrantLockTest {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
private ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
private void read(){
try {
readLock.lock();
System.out.println(Thread.currentThread().getName()+"读操作开始");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"读操作结束");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
readLock.unlock();
}
}
private void write(){
try {
writeLock.lock();
System.out.println(Thread.currentThread().getName()+"写操作开始");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"写操作结束");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest r = new ReentrantLockTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
r.read();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
r.write();
}
}, "t2");
Thread t3= new Thread(new Runnable() {
@Override
public void run() {
r.read();
}
}, "t3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
r.write();
}
}, "t4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果:
t3读操作开始
t1读操作开始
t3读操作结束
t1读操作结束
t2写操作开始
t2写操作结束
t4写操作开始
t4写操作结束
针对ReentrantLock方法的补充:
1. getHoldCount() 查询当前线程保持此锁的次数,也就是执行此线程执行lock方法的次数
2.getQueueLength()返回正等待获取此锁的线程估计数,比如启动10个线程,1个线程获得锁,此时返回的是9
3.getWaitQueueLength(Condition condition)返回等待与此锁相关的给定条件的线程估计数。比如10个线程,用同一个condition对象,并且此时这10个线程都执行了condition对象的await方法,那么此时执行此方法返回10
4.hasWaiters(Condition condition)查询是否有线程等待与此锁有关的给定条件(condition),对于指定contidion对象,有多少线程执行了condition.await方法
5.hasQueuedThread(Thread thread)查询给定线程是否等待获取此锁
6.hasQueuedThreads()是否有线程等待此锁
7.isFair()该锁是否公平锁
8.isHeldByCurrentThread() 当前线程是否保持锁锁定,线程的执行lock方法的前后分别是false和true
9.isLock()此锁是否有任意线程占用
10.lockInterruptibly()如果当前线程未被中断,获取锁
11.tryLock()尝试获得锁,仅在调用时锁未被线程占用,获得锁
12.tryLock(long timeout TimeUnit unit)如果锁在给定等待时间内没有被另一个线程保持,则获取该锁
要说明的是: