Java中线程的高级应用
2010-10-05 01:23:09 来源:WEB开发网(4)synchronized代码块
synchronized 方法的主要缺陷在于,若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized方法 ,然后在主方法中调用该synchronized方法来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。
通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) { //允许访问控制的代码 }
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (同步对象,可以是类实例或类)的锁方能执行。由于synchronized 块可以针对任意的代码块,且可任意指定上锁的对象,故灵活性较高。
(5)线程互斥的实例:
编程模拟银行计算利息,由线程管理50个出纳(50个线程),计算全部出纳付出的总利息,其中每个出纳处理10笔钱,每笔款额为1000元,利息为0.1。
import java.applet.Applet; //未采用同步方法时的程序 import java.awt.*; import java.awt.event.*; public class tongbu extends Applet implements Runnable,ActionListener { int Accounts=1000; //每笔款额为1000元 int money,interest,totalMoney; List list=new List(); //定义并产生一个List控件 Button startButton=new Button("开始计算"); public void init() { list.resize(size().width,size().height-50); //设定List控件的大小与Applet相匹配 setLayout(new BorderLayout()); //方位布局 add("Center",list); //定位List控件的位置 startButton.addActionListener(this); add("South",startButton); //在Applet中加入一个"开始计算"按钮 } public void actionPerformed(ActionEvent evt) //响应用户单击"开始计算"按钮的事件 { if(evt.getSource()==startButton) { for(int i=1;i<=50;i++) //产生并启动50个线程(50个出纳) new Thread(this).start(); } } // public synchronized void run() public void run() { for(int i=0;i<10;i++) { totalMoney=totalMoney+Accounts;//统计及显示必须"一气合成"地执行,不允许打断。 interest=interest+(int)(Accounts*0.1); } try { Thread.sleep(10); //目的是适应高档主机 } catch(InterruptedException e) { } String result=String.valueOf(totalMoney)+"--"+String.valueOf(interest); list.addItem(result); } }
计算结果有错(不是逐个累加状态),其原因是所创建的50个线程都要调用calculate()及addlist()方法(注意:一个线程的调用还未结束,另一个线程的调用已经可能开始!),而每执行一次calculate(都修改totalMoney 及interest值;每当两个线程同时调用calculate(),由于CPU的分时执行效果,两个线程交差修改totalMoney 及interest值,非同步执行导致totalMoney的值与interest值不匹配(让一个线程顺序执行完毕后再让另一个线程顺序执行完毕,在某一时刻只允许一个线程访问共享资源)。
改进的措施:将run()方法设置为同步方法(是否可以将calculate() 及addlist()设置为同步方法 ?)
要点:
区分实例对象监视器(在同一个类中的所有非静态同步方法都使用同一个实例对象监视器,一旦某一个对象的同步方法被执行,该对象即获得监视器,只有当该对象的同步方法被完整地执行完毕,其他对象才能获得监视器)和类监视器(在同一个类中的所有静态同步方法都使用同一个类监视器,当同步方法要求访问静态成员数据时应将此同步方法设计为静态同步方法,此时在任意时刻只允许有一个静态同步方法被执行)的不同。
更多精彩
赞助商链接