题记          使用JAVA也有些时间了,头脑里总会闪现出一些似是而非的问题。于是,我考虑建立一个专题,专门来讨论这些问题,初步把它定位在FAQ的形式上。这是第一篇,初步讨论关于同步的问题。          为什么需要同步?     以下是一简单计数器的例子: <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.io.*" %> <html> <body>     <%!       public int number;       private String countFile;      public int number(){          try{              ServletContext application=getServletContext();              countFile=application.getRealPath("/");                     BufferedReader file=new BufferedReader(new FileReader(countFile+"hits.txt"));              number=java.lang.Integer.parseInt(file.readLine());              number++;          }          catch(Exception e){              System.out.println(e);          }          return number;      }      public synchronized void counter(){          number();          try{              File f=new File(countFile+"hits.txt");              PrintWriter pw=new PrintWriter(new FileWriter(f));              pw.print(number);              pw.close();         }         catch(Exception e){             System.out.println(e);         }                   }   %>   <%   if(session.isNew()){           counter();        }   out.println(number);  %> </body> </html>     关键词synchronized定义了同步的概念,它可以作为方法修饰符,亦可作为方法内语句。在多线程条件下它限制了对共享资源的访问。方法counter()锁存地获取和释放IO资源,即持有该对象的lock。这种机制可以避免一个线程在进行文件读写操作时,其他线程如果也操作该资源,会抛出异常的情况。          什么时候需要同步机制?     第一,如果对象的更新影响到只读方法,那么只读方法也应被定义为同步的,例如上面的IO操作。第二,如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为同步的。 
    减少同步     增加无谓的同步控制,几乎和遗漏必要的同步一样糟糕。据文献记载,没有使用同步机制的操作几乎要比使用这一机制的快数倍!原因在于锁存地获取和释放资源,不再通过monitorenter和monitorexit操作码来进行,而是会检查ACC_SYNCHRONIZED属性标记,这一操作是要花费相当的代价。并且,过渡的同步控制可能导致代码死锁,并发度降低。所以应该避免无谓的同步。          注意问题     synchronized关键词一般用于虚拟锁,锁住的不是方法或代码,而是调用这个方法的对象。例如,对于一个构造函数Test(int n),由于变量n的不同,可以构造出不同的Test对象a和b,如果a、b同时访问同步区域,结果只会使synchronized形同虚设!     a和b如果要同时访问同步方法,只有该同步方法为static时才能达到同步的目的,否则,a调用a的方法,b调用b的方法,即使方法声明为同步的,但在不同对象域中它们根本达不到同步的目的。  
 
  |