线程同步
Java程序中可以存在多个线程,但是在处理多线程问题时,必须注意这样一个问题:当两个或多个线程同时访问同一个变量,并且一些线程需要修改这个变量。程序应对这样的问题做出处理,否则可能发生混乱,比如一个工资管理负责人正在修改雇员的工资表,而一些雇员也正在领取工资,如果允许这样做必然初夏 混乱。因此,工资管理负责人正在修改工资表(包括他喝杯茶休息一会),将不允许任何雇员领取工资,也就是说这些雇员必须等待。
所谓线程同步就是若干个线程都需要使用一个synchronized(同步)修饰的方法,即程序中的若干个线程都需要使用一个方法,而这个方法用synchronized给予了修饰,多个线程调用synchronized方法必须遵守同步机制。
线程同步机制:当一个线程A使用synchronized方法时,其他线程想使用这个synchronized方法时就必须等待,直到线程A使用完该synchronized方法。
在使用多线程解决许多实际问题时,可能要吧某些修改数据的方法用方法用关键字synchronized来修饰,即使用同步机制。
下面的例子中有两个线程:会计和出纳,他俩共同拥有一个账本,他俩都可以使用saveOrTake(int amount)方法对账本进行访问,会计使用saveOrTake(int amount)方法时,向账本上写入存钱记录;出纳使用saveOrTake(int amount)方法时,向账本写入取钱记录。因此,当会计正在使用saveOrTake(int amount)时,出纳被禁止使用,反之也是这样。比如,会计使用saveOrTake(int amount)时,在账本上存入300万元,但在存入这笔钱时,每存入100万,就喝口茶,那么会计喝茶休息时,存钱这件事还没结束,即会计还没有使用saveOrTake(int amount)方法,出纳仍不能使用saveOrTake(int amount);出纳使用saveOrTake(int amount)时,在账本上取出150万元,但在取出这笔钱时,每取出50万元,就喝口茶,那么出纳喝茶休息时,会计不能使用saveOrTake(int amount),也就是说,程序要保证其中一人使用saveOrTake(int amount)时,另一个人将必须等待,即saveOrTake(int amount)方法应当是一个synchronized方法。
例子:
Example12_7.java
package com.liu;
public class Example12_7 {
public static void main(String[] args) {
Bank bank=new Bank();
bank.setMoney(200);
Thread accountant,cashier;
accountant=new Thread(bank);
cashier=new Thread(bank);
accountant.setName("会计");
cashier.setName("出纳");
accountant.start();
cashier.start();
}
}
Bank.java
package com.liu;
public class Bank implements Runnable{
int money=200;
public void setMoney(int n){
money=n;
}
public void run(){
if(Thread.currentThread().getName().equals("会计"))
saveOrTake(300);
else if(Thread.currentThread().getName().equals("出纳"))
saveOrTake(150);
}
public synchronized void saveOrTake(int amount){//注意这里是同步即有synchronized
if(Thread.currentThread().getName().equals("会计")){
for(int i=1;i<=3;i++){
money=money+amount/3;
System.out.println(Thread.currentThread().getName()+"存入"+amount/3+",账上有"+money+"万,休息一会再存");
try{Thread.sleep(1000);
}catch(InterruptedException e){}
}
}else if(Thread.currentThread().getName().equals("出纳")){
for(int i=1;i<=3;i++){
money=money-amount/3;
System.out.println(Thread.currentThread().getName()+"取出"+amount/3+",账上有"+money+"万,休息一会在取");
try{
Thread.sleep(1000);
}catch(InterruptedException e){}
}
}
}
}
其运行结果:(一条一条输出到控制台,可以自己尝试运行查看效果)
当Bank.java 去掉saveOrTake方法的同步修饰synchronized时,观察运行结果。
(存在问题,请自己实际操作,两条同时输出,结果有问题)