例1:
public class ThreadTest implements Runnable {     public synchronized void run() {
         for (int i = 0; i < 10; i++) {
             System.out.print(" " + i);
         }
     }     public static void main(String[] args) {
         for (int i = 0; i < 20; i++) {
             Runnable r1 = new ThreadTest();
             Runnable r2 = new ThreadTest();
             Thread t1 = new Thread(r1);
             Thread t2 = new Thread(r2);
             t1.start();
             t2.start();
         }
     }
}/**synchronized关键字用于保护共享数据。请大家注意"共享数据",你一定要分清哪些数据是共享数据 这个程序中synchronized关键字保护的不是共享数据(其实在这个程序中synchronized关键字没有起到任何作用,此程序的运行结果是不可预先确定的)。这个程序中的t1,t2是两个对象(r1,r2)的线程。JAVA是面向对象的程序设计语言,不同的对象的数据是不同的,r1,r2有各自的run()方法,而synchronized使同一个对象的多个线程,在某个时刻只有其中的一个线程可以访问这个对象的synchronized数据。每个对象都有一个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被synchronized修饰的数据将被上锁(因为"锁标志"被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它线程才有机会访问synchronized数据。**/例2:
public class ThreadTest implements Runnable {     public synchronized void run() {
         for (int i = 0; i < 10; i++) {
             System.out.print(" " + i);
         }
     }     public static void main(String[] args) {
         for (int i = 0; i < 20; i++) {
             Runnable r = new ThreadTest();
             Thread t1 = new Thread(r);
             Thread t2 = new Thread(r);
             t1.start();
             t2.start();
         }
     }
}
/**因为这里的synchronized保护的是共享数据。t1,t2是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run()方法时,由于run()受synchronized保护,所以同一个对象的其他线程(t2)无法访问synchronized方法(run方法)。只有当t1 执行完后t2才有机会执行。**/例3:/*
 * 创建日期 2008-4-30
 *
 * 更改所生成文件模板为
 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
package thread;class BlankSaving //储蓄账户
{
    private static int money=10000;
    public void add(int i){
        money=money+i;
        System.out.println("Husband 向银行存入了 [¥"+i+"]");
    }
    public void get(int i){
        money=money-i;
        System.out.println("Wife 向银行取走了 [¥"+i+"]");
        if(money<0)System.out.println("余额不足!"); 
    }
    public int showMoney(){return money;}
} class Operater implements Runnable{
    String  name;
    BlankSaving bs;
    public Operater(BlankSaving b,String s){
        name=s;
        bs=b;
    }
    public synchronized static void oper(String name,BlankSaving bs){
        if(name.equals("husband")){
            try{
                for(int i=0;i<10;i++){
                    Thread.currentThread().sleep((int)(Math.random()*300));
                    bs.add(1000);
                }
            }catch(InterruptedException e){
            }
        }else{
            try{
                for(int i=0;i<10;i++){
                    Thread.currentThread().sleep((int)(Math.random()*300));
                    bs.get(1000);
                }
            }catch(InterruptedException e){}
        }
    }
        public void run(){
        oper(name,bs);    } 
}public class BankTest {
    public static void main(String[] args)throws InterruptedException{
        BlankSaving bs=new BlankSaving();
        Operater o1=new Operater(bs,"husband");
        Operater o2=new Operater(bs,"wife");
        Thread t1=new Thread(o1);
        Thread t2=new Thread(o2);
        t1.start();
        t2.start();
        Thread.currentThread().sleep(500);
    }
}
/**
 * 下面是其中一次的执行结果:
---------first--------------
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Husband 向银行存入了 [¥1000]看到了吗,这可不是正确的需求,在husband还没有结束操作的时候,wife就插了进来,这样很可能导致意外的结果。
解决办法很简单,就是将对数据进行操作方法声明为synchronized,当方法被该关键字声明后,
也就意味着,如果这个数据被加锁,只有一个对象得到这个数据的锁的时候该对象才能对这个数据进行操作。
也就是当你存款的时候,这笔账户在其他地方是不能进行操作的,只有你存款完毕,银行管理人员将账户解锁,
其他人才能对这个账户进行操作。
修改public static void oper(String name,BlankSaving bs)为
public synchronized static void oper(String name,BlankSaving bs),再看看结果:Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Husband 向银行存入了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]
Wife 向银行取走了 [¥1000]当丈夫完成操作后,妻子才开始执行操作,这样的话,对共享对象的操作就不会有问题了。
*/例1和例2我都可以理解,唯独例3有些不明白。例3的以下方法中:
public class BankTest {
    public static void main(String[] args)throws InterruptedException{
        BlankSaving bs=new BlankSaving();
        Operater o1=new Operater(bs,"husband");
        Operater o2=new Operater(bs,"wife");
        Thread t1=new Thread(o1);
        Thread t2=new Thread(o2);
        t1.start();
        t2.start();
        Thread.currentThread().sleep(500);
    }
}o1和o2是两个不同的对象实例,为什么调用public synchronized static void oper(String name,BlankSaving bs)
方法后可以实现同步的效果。按我的理解,t1和t2在调用public synchronized static void oper(String name,BlankSaving bs)方法时t1线程应该不会等待t2线程,即t1和t2线程可同时执行public synchronized static void oper(String name,BlankSaving bs)这个方法。可实际情况是t2线程必须等待t1线程执行完public synchronized static void oper(String name,BlankSaving bs)方法后才能接着执行public synchronized static void oper(String name,BlankSaving bs)方法。
在网上查了好多关于synchronized 的解释,可还是对例3的执行情况不理解。
希望您能帮我解释一下这个问题,非常感谢!!!

解决方案 »

  1.   

    方法如果加上synchronized修饰那么
    此方法在某一时刻只能被一个线程访问
    也就是说只能被一个对象调用
    所以当t1调用oper()时
    t2就只能等t1调用oper,t2才能调用oper
      

  2.   

    synchronized 非静态方法只是保护当前实例
    synchronized 静态方法才是包括类所有共享的数据
      

  3.   

    你问错人了,不好意思.JAVA我不太懂.
      

  4.   

    非常感谢大家的帮忙,synchronized 静态方法包括类所有共享的数据 是什么意思啊。按我的理解,线程只有在得到Operater的 java.lang.Class 的锁,则public synchronized static void oper(String name,BlankSaving bs)这个方法就只允许Operater这个类的其中一个线程访问,那这个被同步的静态方法就只允许一个线程访问。另外如改写代码如下,
    class BlankSaving //储蓄账户 

        private static int money=10000; 
        public synchronized void add(int i){ 
            money=money+i; 
            System.out.println("Husband 向银行存入了 [¥"+i+"]"); 
        } 
        public void get(int i){ 
            money=money-i; 
            System.out.println("Wife 向银行取走了 [¥"+i+"]"); 
            if(money <0)System.out.println("余额不足!");  
        } 
        public int showMoney(){return money;} 
    }  class Operater implements Runnable{ 
        public Operater(){ 
        } 
        public void oper(){ 
            BlankSaving bs = new BlankSaving();
            bs.add(2);//被synchronized 
        } 
             public void run(){ 
            oper();     }  
    } public class BankTest { 
        public static void main(String[] args)throws InterruptedException{ 
            BlankSaving bs=new BlankSaving(); 
            Operater o1=new Operater(); 
            
            Thread t1=new Thread(o1); 
            Thread t2=new Thread(o1); 
            t1.start(); 
            t2.start(); 
            Thread.currentThread().sleep(500); 
        } 
    } 这是当执行到bs.add(2)方法时,bs.add(2)方法是不是也是只允许t1线程访问结束后t2线程才能访问。如果不能实现同步的话,怎样才能让bs.add(2)方法实现同步。
      

  5.   

    静态方法static
    如果不是线程,一个简单的static变量
    public class Test{
    public static int i;
    }
    那么这个i将被所有的类使用.
    Test t1=new Test();
    t1.i=2
    则当
    Test t2=new Test();
    System.out.println(t2) //2所以那个静态的同步方法被所有的类实例使用。是同一个方法