synchronized修饰的对象,该对象就是隐式锁,例子如下
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
private int count = 10;
private Object object = new Object();
@Override
public void run() {
while (true) {
synchronized (object) {
if (count > 0) {
System.out.println("买票开始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("余票" + count+Thread.currentThread().getName());
}else {
break;
}
}
}
}
}
还有同步方法也就是synchronized修饰的方法,该方法就是隐式锁.例子如下
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
private int count = 10;
private Object object = new Object();
@Override
public void run() {
while (true) {
boolean b = sale();
if (!b) {
break;
}
}
}
public synchronized boolean sale() { //在方法返回值前面加synchronized变成同步方法
if (count > 0) {
System.out.println("买票开始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("余票" + count + Thread.currentThread().getName());
return true;
}
return false;
}
}
显示锁是由Lock类定义的锁,更符合面向对象,有上锁,解锁的步骤
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable {
private int count = 10;
private Object object = new Object();
private Lock l = new ReentrantLock();
@Override
public void run() {
l.lock();
while (true) {
if (count > 0) {
System.out.println("买票开始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("余票" + count + Thread.currentThread().getName());
} else {
break;
}
}
l.unlock();
}
}
了解了隐式锁和显示锁,那么他们区别在哪
- 公平锁与非公平锁: synchronized是非公平锁,其实除了Lock类设置为公平锁以外都是非公平锁,他们选择下一个线程是随机就近进入,抢占式的方式,而Lock类锁传true设置后是按线程申请顺序排队进入
- synchronized底层依赖于软件层面上的JVM,而Lock类依赖于特殊的CPU指定,可以认为不受JVM的约束,并可以通过其他语言平台来完成底层的实现。在并发量较小的多线程应用程序中,Lock类与synchronized性能相差无几,但在高并发量的条件下,synchronized性能会迅速下降几十倍,而ReentrantLock的性能却能依然维持一个水准,因此我们建议在高并发量情况下使用ReentrantLock。
- 使用Synchronized在线程发生异常时会自动释放锁,因此不会发生异常死锁。Lock异常时不会自动释放锁,所以需要在finally中实现释放锁
- Lock是可以中断锁,Synchronized是非中断锁,必须等待线程执行完成释放锁
- 总的来说Lock可以使用读锁提高多线程读效率,更直观方便