传统的线程通信
Object 类下的 wait() notify() notifyAll()
这三个方法必须由同步监视器来调用
- 对于synchronized修饰的同步方法 默认的同步监视器就是this
- 对于synchronized修饰的同步代码块,同步监视器就是括号后面的对象,必须由该对象调用这三个方法
下面的同步监视器就是account
public class DrawThread extends Thread{
//模拟用户账户
private Account account;
//当前取钱线程希望取的钱数
private double drawAmount;
public DrawThread(){}
public DrawThread(String name, Account account, double drawAmount){
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//当多个线程修改同意数据会出现数据安全问题
@Override
public void run(){
synchronized (account) {
//取钱数小于账户余额
if (account.getBalance() >= drawAmount) {
System.out.println(getName() + "取钱成功" + drawAmount);
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
//修改余额
account.setBalance(account.getBalance() - drawAmount);
System.out.println("余额为:" + account.getBalance());
} else {
System.out.println(getName() + "余额不足 取钱失败");
}
}
}
}
使用Condition控制线程通信
程序不使用synchronized关键字保证同步,那么直接使用Lock对象保证同步。
Java 中使用了一个Condition类来保持协调,使用Condition可以让得到Lock对象却无法继续执行的线程释放Lock对象。
也就是Lock代替了synchronized Condition 代替了同步监视器
public class Account {
//定义锁对象
private final ReentrantLock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
//封装 账户编号 账户余额
private String accountNo;
private double balance;
//账户是否有钱的标志
boolean flag = false;
public Account(){}
public Account(String accountNo, double balance){
this.accountNo = accountNo;
this.balance = balance;
}
public void draw(double drawAmount){
lock.lock();
try {
if(!flag){
cond.await();
}else{
//取钱数小于账户余额
if (balance >= drawAmount) {
System.out.println(Thread.currentThread().getName() + "取钱成功" + drawAmount);
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
//修改余额
balance -= drawAmount;
flag = false;
System.out.println("余额为:" + balance);
cond.signalAll();
} else {
System.out.println(Thread.currentThread().getName() + "余额不足 取钱失败");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
使用阻塞队列 BlockQueue
生产者放入集合元素的时候,如果已经满了会阻塞,拿元素的时候,如果是空的会阻塞。
public class Producer extends Thread{
private BlockingQueue<String> bq;
public Producer(BlockingQueue<String> bq){
this.bq = bq;
}
@Override
public void run(){
String[] strArr = new String[]{
"java",
"Struts",
"Spring"
};
for (int i = 0; i < 99999999; i++) {
System.out.println(getName()+"生产者准备生产集合元素");
try{
Thread.sleep(200);
bq.put(strArr[i % 3]);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(getName()+"生产完成"+bq);
}
}
}
class Consumer extends Thread{
private BlockingQueue<String> bq;
public Consumer(){}
public Consumer(BlockingQueue<String> bq){
this.bq = bq;
}
@Override
public void run(){
System.out.println(getName()+"消费者开始消费集合元素"+bq);
try {
Thread.sleep(200);
bq.take();
}catch (Exception e){
e.printStackTrace();
}
System.out.println(getName()+"消费完成"+bq);
}
}
public class BlockingQueueTest2 {
public static void main(String[] args) {
BlockingQueue<String> bq = new ArrayBlockingQueue<>(1);
new Producer(bq).start();
new Producer(bq).start();
new Producer(bq).start();
new Consumer(bq).start();
}
}