synchronized
synchronized是内置锁,分为对象锁和类锁。可以用于方法,代码块中。如果是方法,锁的是this对象,如果是代码块,锁的是指定的那个对象。类锁其实是一个不太准确的说法,应用于静态方法,本质上锁的是该Class对象
等待和通知的标准范式
等待方
- 获取对象锁
- 检查条件,条件不满足,调用对象wait
- 执行业务代码
synchronized(对象){
while(不满足条件){
对象.wait();
}
//执行业务代码
}
通知方
- 获取对象锁
- 修改条件
- 发出通知
synchronized(对象){
执行业务代码,修改条件
调用对象的notify/notifyAll,发出通知
}
注意:
wait调用之后,会立刻释放锁。
notify/notifyAll不会马上释放锁,会等到synchronized(对象){}代码块执行结束,才会释放锁。
notify只会通知一个线程,如果多个线程wait,那么用notifyAll。
Thread.yield和Thread.sleep,不会释放锁
实战生产消费者模型
wait/notifyAll
/**
* 快递公里数和地点变化通知
*/
public class Express {
private int km = 0; //公里数
private String site = "BeiJing"; //地点
//发出公里数发生变化的通知
public synchronized void changeKm(int km) {
this.km = km;
notifyAll();
}
//发出地点发生变化的通知
public synchronized void changeSite(String site) {
this.site = site;
notifyAll();
}
public synchronized void waitKm() {
while (this.km <= 10) {
try {
wait();
System.out.println(Thread.currentThread().getName() + " km notify");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " km change");
}
public synchronized void waitSite() {
while (this.site.equals("BeiJing")) {
try {
wait();
System.out.println(Thread.currentThread().getName() + " site notify");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " site change");
}
public static void main(String[] args) throws InterruptedException {
Express express = new Express();
//三个等待公里数变化的线程
for (int i = 0; i < 3; i ++) {
Thread thread = new Thread("thread km - " + i) {
@Override
public void run() {
express.waitKm();
}
};
thread.start();
}
//三个等待地点变化的线程
for (int i = 0; i < 3; i ++) {
Thread thread = new Thread("thread site - " + i) {
@Override
public void run() {
express.waitSite();
}
};
thread.start();
}
Thread.sleep(1000);
express.changeKm(100);
// express.changeSite("shagnhai");
}
}
Lock/Condition
public class ExpressLock {
private int km = 0;
private String site = "Beijing";
private Lock lock = new ReentrantLock();
private Condition kmCondition = lock.newCondition();
private Condition siteCondition = lock.newCondition();
public void changeKm() {
try {
lock.lock();
km = 100;
kmCondition.signalAll();
}finally {
lock.unlock();
}
}
public void changeSite() {
try {
lock.lock();
site = "ShangHai";
siteCondition.signalAll();
}finally {
lock.unlock();
}
}
public void waitKm() {
try {
lock.lock();
while (km <= 0) {
kmCondition.await();
System.out.println(Thread.currentThread().getName() + " km notify");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println(Thread.currentThread().getName() + " km change");
}
public void waitSite() {
try {
lock.lock();
while (site.equals("Beijing")) {
siteCondition.await();
System.out.println(Thread.currentThread().getName() + " site notify");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
System.out.println(Thread.currentThread().getName() + " site change");
}
public static void main(String[] args) {
ExpressLock expressLock = new ExpressLock();
//等待公里数变化的线程
for (int i = 0; i < 3; i ++) {
Thread thread = new Thread() {
@Override
public void run() {
expressLock.waitKm();
}
};
thread.start();
}
//等到地点变化的线程
for (int i = 0; i < 3; i ++) {
Thread thread = new Thread() {
@Override
public void run() {
expressLock.waitSite();
}
};
thread.start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
expressLock.changeKm();
expressLock.changeSite();
}
}