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():从功能来看,与判断组合,它也保证了线程的执行顺序。
死锁:程序因为遭到线程都在“等待”状态,而无法运行的情况。