可以通过使用synchronized关键字修改方法来同步对方法的访问.当调用方法时,调用线程进入对象监视器,对象监视器锁住对象.在对象被锁的同时,其他线程不能进入方法,也不能进入对象定义的其他同步方法.当线程从方法返回时,监视器为对象解锁,允许下一个线程使用对象.因此,同步的实现实质上不需要进行程序设计.
下面的程序通过控制对名为sumArray()的方法的访问来演示同步.sumArray()方法对一个整数数组的元素进行求和运算.
public class test2 { // @param args public static void main(String args[]) { int a[] = {1,2,3,4,5}; MyThread mt1 = new MyThread("child#1",a); MyThread mt2 = new MyThread("child#2",a); try { mt1.thrd.join(); mt2.thrd.join(); }catch(InterruptedException exc) { System.out.println("error"); } } } class SumArray { private int sum; synchronized int sumArray(int nums[]) { for(int i=0;i<nums.length;i++) { sum += nums[i]; System.out.println("tunning total for "+Thread.currentThread().getName()+"is "+sum); try { Thread.sleep(10); }catch(InterruptedException exc) { System.out.println("thread interrupted"); } } return sum; } } class MyThread implements Runnable { Thread thrd; static SumArray sa = new SumArray(); int a[]; int answer; MyThread(String name,int nums[]) { thrd = new Thread(this,name); a = nums; thrd.start(); } public void run() { int sum; System.out.println(thrd.getName()+" starting"); answer = sa.sumArray(a); System.out.println("Sum for "+thrd.getName()+" is "+answer); } }
输出:
child#2 starting child#1 starting tunning total for child#2is 1 tunning total for child#2is 3 tunning total for child#2is 6 tunning total for child#2is 10 tunning total for child#2is 15 tunning total for child#1is 16 Sum for child#2 is 15 tunning total for child#1is 18 tunning total for child#1is 21 tunning total for child#1is 25 tunning total for child#1is 30 Sum for child#1 is 30
让我们仔细研究一下这个程序.程序创建了三个类.第一个类是SumArray,他包含对整数数组求和的sunArray()方法.第二个类是MyThread,他使用一个SumArray类型的static对象获取一个整数数组的和.这个对象被命名为sa,因为他被声明为static,所以只有一个副本被MyThread的所有示例共享.第三个类是Sync,他创建了两个线程来计算整数数组的和.
在sumArray()内部调用sleep(),以便在发生任务切换时,有意允许任务切换发生,但这是不可能发生的.因为sumArray()被同步了,所以在一个时刻只有一个线程可以使用他.因此,当第二个子线程开始执行时,他在第一个子线程用完sumArray()之前是不会进入sumArray()的,这样就确保了生成正确的结果.
为彻底理解synchronized的作用,请将其从sumArray()的声明中删除.在这之后,sunArray()就不再同步了,任何数量的线程都可以同时使用他.这样带来的问题就是存储在sum中的综合可以被每个线程通过调用static对象的sa的sumArray()改变.因此当两个线程同时调用sa.sumArray()时,就会因为sum反应的是两个混合在一起的线程的总和而产生的错误的结果.例如,下面是将synchronized从sumArray()声明中删除后的程序的运行示例结果:
child#1 starting child#2 starting tunning total for child#1is 1 tunning total for child#2is 2 tunning total for child#1is 6 tunning total for child#2is 6 tunning total for child#1is 9 tunning total for child#2is 12 tunning total for child#2is 16 tunning total for child#1is 20 tunning total for child#2is 30 tunning total for child#1is 30 Sum for child#2 is 30 Sum for child#1 is 30
正如输出所示,两个子线程正在并发调用sumArray(),而sum的值则被破坏了,在继续讨论之前,我们先回顾一下同步方法的一些要点:
通过在声明钱加上synchronized来创建同步方法
对于任何给定对象,一旦同步方法被调用,就会锁住对象,其他线程的执行就不能使用同一对象上的同步方法.
其他线程视图使用正在使用的对象时将进入等待状态,直到对象解锁为止.
当线程离开同步方法时,对象被解锁.