线程通信
wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法和notifyAll()方法来唤醒该线程
notify():唤醒在此同步监视器上等待的单个线程,会选择唤醒其中的任意一个线程,选择是任意的。只有当前线程放弃对该同步监视器的锁定后(调用wait()方法),才会执行被唤醒的线程。
notifyAll():唤醒在此同步监视器上等待的所有线程。只有放弃对该同步监视器的锁定后才可以执行被唤醒的线程。
采用Object中的方法模拟存取取钱的操作。只有当存钱后才执行取钱操作。
账户类:
public class Account {
private String accountNo;
private double balance;
/**
* 是否存钱标示
*/
private boolean flag = false;
public Account(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
/**
* 取钱
*
* @param drawAmount
*/
public synchronized void draw(double drawAmount) {
try {
if (this.flag) {
System.out.println("开始取钱:" + drawAmount);
this.balance -= drawAmount;
this.flag = false;
notifyAll();
} else {
System.out.println("当前无钱,");
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 存钱
*
* @param depositAmount
*/
public synchronized void deposit(double depositAmount) {
try {
if (!this.flag) {
System.out.println("开始存钱" + depositAmount);
this.balance += depositAmount;
this.flag = true;
notifyAll();
} else {
System.out.println("当前已存钱");
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
存钱线程:
public class DepositThread implements Runnable {
private Account account;
private Integer depositAmount;
public DepositThread(Account account, Integer depositAmount) {
this.account = account;
this.depositAmount = depositAmount;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.deposit(this.depositAmount);
}
}
}
取钱线程:
public class DrawThread implements Runnable {
private Account account;
private Integer drawAmount;
public DrawThread(Account account, Integer drawAmount) {
this.account = account;
this.drawAmount = drawAmount;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
account.draw(this.drawAmount);
}
}
}
启动:
public class TestMain {
public static void main(String[] args) {
Account account = new Account("123456", 0);
new Thread(new DepositThread(account, 800), "存钱者").start();
new Thread(new DrawThread(account, 800), "取钱者").start();
}
}
当执行存钱操作,增加该账户的余额,将是否存钱标示符改为true,同时唤醒该同步锁上的其他线程,存钱操作再次执行,则该线程进入睡眠状态,取钱线程开始执行,减少余额,将是否存钱标示符该为false,唤醒该同步锁上的其他资源。
简化版
@Test
public void test13() throws InterruptedException {
Object obj=new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
System.out.println("t1 获取到锁");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 再次获取到锁");
}
}
}).start();
Thread.sleep(100);
synchronized (obj){
System.out.println("main 获取到锁");
Thread.sleep(10000);
obj.notify();
}
while (Thread.activeCount()>2){}
System.out.println("run over");
}
使用LockSupport
/**
* LockSupport使用
*/
@Test
public void test02(){
Thread t01=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始阻塞");
LockSupport.park();
System.out.println("阻塞结束");
}
});
t01.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("解除t01的阻塞");
LockSupport.unpark(t01);
while (Thread.activeCount()>2){}
System.out.println("run over");
}
LockSupport使用案例二
Thread t01 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始等待");
long beginTime = System.currentTimeMillis();
//停顿10秒
long waitTime=TimeUnit.NANOSECONDS.convert(10, TimeUnit.SECONDS);
LockSupport.parkNanos(waitTime);
System.out.println("等待结束:"+(System.currentTimeMillis()-beginTime));
}
});
t01.start();
Thread.sleep(2000);
System.out.println("开始唤醒");
LockSupport.unpark(t01);
while(Thread.activeCount()>2) {}
@Test
public void test03() throws InterruptedException {
Object obj=new Object();
Thread t01=new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
System.out.println("开始阻塞");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束阻塞");
}
}
});
t01.start();
Thread.sleep(2000);
synchronized (obj){
System.out.println("唤醒obj上的线程");
obj.notify();
}
while (Thread.activeCount()>2){}
System.out.println("run over");
}
使用案例-两个线程交替执行
@Test
public void test04() {
Object obj01 = new Object();
Thread t01 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj01) {
try {
Thread.sleep(1000);
System.out.println(1);
obj01.notify();
obj01.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t01.start();
Thread t02 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj01) {
try {
Thread.sleep(1000);
System.out.println(2);
obj01.notify();
obj01.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t02.start();
while (Thread.activeCount() > 2) {
}
System.out.println("run over");
}
进阶-三个线程交替执行
Object obj01 = new Object();
Object obj02 = new Object();
Object obj03 = new Object();
Thread t01 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj01) {
try {
Thread.sleep(1000);
System.out.print(1);
synchronized (obj02) {
obj02.notify();
}
obj01.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t01.start();
//让第一个线程先跑起来
Thread.sleep(1000);
Thread t02 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj02) {
try {
Thread.sleep(1000);
System.out.print(2);
synchronized (obj03) {
obj03.notify();
}
obj02.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t02.start();
//让第二个线程执行起来
Thread.sleep(1000);
Thread t03 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (obj03) {
try {
Thread.sleep(1000);
System.out.println(3);
synchronized (obj01) {
obj01.notify();
}
obj03.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
t03.start();
while (Thread.activeCount() > 2) {
}
System.out.println("run over");
参考https://www.cnblogs.com/qingquanzi/p/8228422.html