与网友讨论之初识同步

类别:Java 点击:0 评论:0 推荐:

    题记
   
    使用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的方法,即使方法声明为同步的,但在不同对象域中它们根本达不到同步的目的。

本文地址:http://com.8s8s.com/it/it16442.htm