1.线程同步
关键字:synchronized
百度一下:synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
保证当前线程完整执行该方法后,才能由其他线程调用。
2.以银行存取款为例
public class Bank { private String account; private Integer balance; public Bank(String account, Integer balance) { this.account = account; this.balance = balance; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public Integer getBalance() { return balance; } public void setBalance(Integer balance) { this.balance = balance; } @Override public String toString() { return "Bank{" + "account='" + account + '\'' + ", balance=" + balance + '}'; } //存100 public void saveAccount(){
//加上延时,模拟更加真实 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(this.getBalance()+100); System.out.println("存款后:"+getBalance()); } public void drawAccount(){ Integer temp= getBalance()-200;
//加上延时,模拟更加真实
try { Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} setBalance(temp); System.out.println("取款后:"+getBalance()); } }
//存款 class Save implements Runnable{ private Bank bank; public Save(Bank bank){ this.bank=bank; } @Override public void run() { bank.saveAccount(); } } //取款 class Draw implements Runnable{ private Bank bank; public Draw(Bank bank){ this.bank=bank; } @Override public void run() { bank.drawAccount(); } } public class BankTest { public static void main(String[] args) { Bank bank=new Bank("Sir li",1000); Save save=new Save(bank); Draw draw=new Draw(bank); Thread thread=new Thread(save); Thread thread1=new Thread(draw); thread.start(); thread1.start(); try { thread.join(); thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank); } }
运行结果:
存款后:1100 取款后:1100 Bank{account='Sir li', balance=1100}
可以看到程序是:在执行了saveAccount()后,balance=1000+100, 在准备执行drawAccount()时,碰到了延时,没有执行 setBalance(temp),直接执行输出语句,最后时主线程中的语句,join()保证了线程的执行顺序没有问题,但是跳过了方法中某些语句的执行。
解决办法:
关键字:synchronized 。给方法加锁
运行结果:正常
存款后:1100 取款后:900 Bank{account='Sir li', balance=900}
3.线程间通信
关键字:wait(),死锁,notify(),notifyAll()
举例:生产与消费。 生产n个,消费 n个,来看看程序如何处理
public class Queue { private int n; public synchronized int getN() { System.out.println("消费"+n); return n; } public synchronized void setN(int n) { System.out.println("生产"+n); this.n = n; } }
class Producer implements Runnable{ private Queue queue; public Producer(Queue queue){ this.queue=queue; } @Override public void run() { int i=0; while (true){ queue.setN(i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ private Queue queue; public Consumer(Queue queue){ this.queue=queue; } @Override public void run() { while (true){ queue.getN(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class ProducerTest { public static void main(String[] args) { Queue queue=new Queue(); Producer producer=new Producer(queue); Consumer consumer=new Consumer(queue); Thread thread=new Thread(producer); Thread thread1=new Thread(consumer); thread.start(); thread1.start(); } }
运行结果
生产0 消费0 生产1 //生产一次消费了两次,程序还是有问题的 消费1 消费1 生产2 消费2
程序应该满足这样的要求:在没有生产的时候是不能消费的,消费的线程需要”等待“。同样在没有被消费之前,也是不能生产的,生产线程需要的”等待“。
public class Queue { private int n; boolean isHave=false;// 增加判断条件 public synchronized int getN() { if (!isHave){ try { wait(); //当没有生产的时候,进入阻塞状态 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费"+n); isHave=false; return n; } public synchronized void setN(int n) { if(isHave){ try { wait(); //在没有消费的时候,进行阻塞状态 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产"+n); this.n = n; isHave=true; } }
运行结果:
生产0 消费0 生产1 消费1 生产2//程序停止输出了,这时候进入了死锁状态,线程之间都在互相等待,需要执行唤醒操作
解决办法:
在getN(),setN()方法中添加:notifyAll();//唤醒线程
结果正常了。。。
4.总结
join():会让当前线程执行完毕,再去执行别的线程。保证了线程的执行顺序。
sychronized: 让被修饰的方法完整的执行。
wait():从功能来看,与判断组合,它也保证了线程的执行顺序。
死锁:程序因为遭到线程都在“等待”状态,而无法运行的情况。