使用同步方法

可以通过使用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来创建同步方法
对于任何给定对象,一旦同步方法被调用,就会锁住对象,其他线程的执行就不能使用同一对象上的同步方法.
其他线程视图使用正在使用的对象时将进入等待状态,直到对象解锁为止.
当线程离开同步方法时,对象被解锁.