主要方法:
synchronized 代码简洁(关键字,是属于语言层面实现同步)
Lock:获取锁可以被中断,超时获取锁,尝试获取锁,读多写少用读写锁(是JDK提供的一个接口,来实现同步)
public class LockDemo {
static Lock lock = new ReentrantLock();
static int count;
public void increase(int num){
lock.lock();//获取锁
try{
count = count + num;
}finally {
lock.unlock();
}
}
public synchronized void increase_syn(int num){
count = count + num;
}
//synchronized方法调用另一个synchronized方法,可重入锁,释放锁时,一个一个释放
public synchronized void syn2(int num){
increase_syn(num);
}
}
如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的,不满足,就是非公平的
非公平的效率一般来讲更高
ReentrantLock默认非公平锁
实现类:ReentrantReadWriteLock
同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读和写都被阻塞
示例:ReentrantReadWriteLock 与 synchronized的对比
public class GoodServiceLock implements GoodService{
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock();
private GoodInfo goodInfo;
public GoodServiceLock(GoodInfo goodInfo){
this.goodInfo = goodInfo;
}
@Override
public GoodInfo getNum() {
readLock.lock();
try {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return goodInfo;
}finally {
readLock.unlock();
}
}
@Override
public void setNum(int number) {
writeLock.lock();
try {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodInfo.changeNumber(number);
}finally {
writeLock.unlock();
}
}
}
public class GoodServiceSyn implements GoodService{
private GoodInfo goodInfo;
public GoodServiceSyn(GoodInfo goodInfo){
this.goodInfo = goodInfo;
}
@Override
public synchronized GoodInfo getNum() {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.goodInfo;
}
@Override
public synchronized void setNum(int number) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodInfo.changeNumber(number);
}
}
public class GoodTest {
private static int writeNum = 2;
private static int readNum = 5;
static class ReadGoodThread extends Thread {
private GoodService goodService;
public ReadGoodThread(GoodService goodService) {
this.goodService = goodService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {//操作100次
goodService.getNum();
}
System.out.println(Thread.currentThread().getName() + "读取商品数据耗时:"
+ (System.currentTimeMillis() - start) + "ms");
}
}
static class WriteGoodThread extends Thread {
private GoodService goodService;
public WriteGoodThread(GoodService goodService) {
this.goodService = goodService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
Random r = new Random();
for (int i = 0; i < 10; i++) {//操作10次
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodService.setNum(r.nextInt(10));
}
System.out.println(Thread.currentThread().getName()
+ "写商品数据耗时:" + (System.currentTimeMillis() - start) + "ms---------");
}
}
public static void main(String[] args) {
GoodInfo goodInfo = new GoodInfo(100000, 10000);
GoodService goodsService = new GoodServiceSyn(goodInfo);
// GoodService goodsService = new GoodServiceLock(goodInfo);
for (int i = 0; i < writeNum; i++) {
Thread setT = new Thread(new WriteGoodThread(goodsService));
for (int j = 0; j < readNum; j++) {
Thread getT = new Thread(new ReadGoodThread(goodsService));
getT.start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
setT.start();
}
}
}
运行结果:
synchronized:
Thread-23读取商品数据耗时:3112ms
Thread-7读取商品数据耗时:3655ms
Thread-19读取商品数据耗时:3749ms
Thread-9读取商品数据耗时:4055ms
Thread-21读取商品数据耗时:4033ms
Thread-11读取商品数据耗时:4195ms
Thread-15读取商品数据耗时:4330ms
Thread-17读取商品数据耗时:4820ms
Thread-1写商品数据耗时:4864ms---------
Thread-5读取商品数据耗时:5116ms
Thread-3读取商品数据耗时:5133ms
Thread-13写商品数据耗时:4991ms---------
ReentrantReadWriteLock :
Thread-5读取商品数据耗时:589ms
Thread-3读取商品数据耗时:595ms
Thread-11读取商品数据耗时:594ms
Thread-9读取商品数据耗时:608ms
Thread-7读取商品数据耗时:614ms
Thread-1写商品数据耗时:605ms---------
Thread-21读取商品数据耗时:614ms
Thread-19读取商品数据耗时:619ms
Thread-15读取商品数据耗时:641ms
Thread-23读取商品数据耗时:639ms
Thread-17读取商品数据耗时:649ms
Thread-13写商品数据耗时:589ms---------
在读多写少的场景下,可以看出ReentrantReadWriteLock比synchronized的效率高出很多。
用Lock与Condition实现消息通知(类似与Obejct的wait、notify、notifyAll,但比这个更优,不会出现信号丢失的现象,一个Lock可以创建多个Condition,根据Condition的不同,分别进行await,signal、signalAll)
public class ConditionDemo {
static String CITY = "xianyang";
static Lock lock = new ReentrantLock();
static Condition siteCondition = lock.newCondition();
static Condition kmCondition = lock.newCondition();
private String site;
private int km;
public ConditionDemo(String site, int km) {
this.site = site;
this.km = km;
}
/* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
public void changeKm(){
lock.lock();
try {
this.km = 101;
kmCondition.signal();
}finally {
lock.unlock();
}
}
/* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
public void changeSite(){
lock.lock();
try {
this.site = "BeiJing";
siteCondition.signal();
}finally {
lock.unlock();
}
}
/*当快递的里程数大于100时更新数据库*/
public void waitKm(){
lock.lock();
try {
while(this.km<=100) {
try {
kmCondition.await();
System.out.println("check km thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the Km is "+this.km+",I will change db");
}
/*当快递到达目的地时通知用户*/
public void waitSite(){
lock.lock();
try {
while(CITY.equals(this.site)) {
try {
siteCondition.await();
System.out.println("check site thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the site is "+this.site+",I will call user");
}
}
运行结果:
check km thread[11] is be notifed.
the Km is 101,I will change db
check site thread[15] is be notifed.
the site is BeiJing,I will call user
check site thread[16] is be notifed.
the site is BeiJing,I will call user
check km thread[12] is be notifed.
the Km is 101,I will change db
根据结果可知,Condition可以单独唤醒某一个或一类的线程。