1、synchronized是java关键字,他是jvm层面; lock是接口(相应的实现比如ReentrantLock);
2、synchronized无法获取到锁的状态, lock可以获取到锁的状态;
3、synchronized是自动锁,如果代码执行完毕或发生异常, 他会自动释放锁的资源, lock手动锁,需要人工进行调用unlock方法进行释放锁的资源, 一般都是放在finally; 如果不释放会发生死锁;
4、synchronized如果线程a获取到锁的资源,发生阻塞,线程b会一直等待, 而lock如果获取不到锁的资源,线程不用等待就结束了;
5、synchronized是可重入、不可中断, 非公平, lock 可重入、 可判断、 可公平(两则皆可);
6、synchronized唤醒线程和等待线程则使用的是Object提供的notify()、wait();方法, 而lock是condition里面提供的signal()、await()方法、 而lock可以获取多个condition可以实现线程循序执行(比如:下面代码1.0);
扩展:
synchronized实现是在jvm中使用monitorenter和monitorexit来实现同步且其中阻塞和唤醒是wait和notify,后者是juc包中的lock层次使用,依赖于AQS来实现加锁和解锁;
lock一般是通过自旋和cas的方式进行给程序加锁,当有一个线程抢到所的资源,其他则进行等待;
synchronized在1.6之前每次都要从内核申请额外的锁资源,这样的话都要设计到用户态和内核态的转换,比较浪费资源,而在大多数情况下只有一个线程操作资源,完全不需要重量级锁的。于是就引入了锁升级的过程。
偏向锁:当只有一个线程去抢一个资源,于是就会使用偏向锁,修改偏向锁的状态(记录锁的状态是在我们对象头里面的markwork记录锁的状态),说明这只有a线程来占有;
轻量级锁:于是又来了b、c线程他们就是把偏向锁的标识去除,然后升级到轻量级锁,他是通过cas+自旋的方式来抢锁的资源(这个抢锁的过程还是偏向与前一个申请偏向锁的a线程);
重量级锁:当a线程获取到锁,b、c线程他们一直在抢锁的资源,抢锁的过程他会消耗cpu的资源,如果十个线程过来,那么这些线程一直抢锁的资源,这样对cpu的资源消耗会比较大的,于是就引入了重量级锁,重量级锁是当我们线程自旋次数达到上限他会升级到重量级锁,向内核申请资源,直接让线程阻塞。这样的话会解决多个线程一个抢锁的资源;
1.0
static final Lock lock = new ReentrantLock();
static final Condition condition = lock.newCondition();
static final Condition condition2 = lock.newCondition();
static final Condition condition3 = lock.newCondition();
private static int num = 0;
psvm {
new Thread(() -> {
while (true) {
lock.lock();
try {
if (num != 0) {
try {
condition.await();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
System.out.println("【" + Thread.currentThread().getName() + "】");
num = 1;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "t1").start();
new Thread(() -> {
while (true) {
lock.lock();
try {
if (num != 1) {
try {
condition2.await();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
System.out.println("【" + Thread.currentThread().getName() + "】");
num = 2;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "t2").start();
new Thread(() -> {
while (true) {
lock.lock();
try {
if (num != 2) {
try {
condition3.await();
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
System.out.println("【" + Thread.currentThread().getName() + "】");
num = 0;
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}, "t3").start();
}
}