java lock講解與用法

來源:互聯網
上載者:User

< type="text/網頁特效"> function windowTitle() { if (location.href.indexOf('is-external=true') == -1) { parent.document.title="Lock (Java Platform SE 6)"; } }
Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構,可以具有差別很大的屬性,可以支援多個相關的 Condition 對象。

鎖是控制多個線程對共用資源進行訪問的工具。通常,鎖提供了對共用資源的獨佔訪問。一次只能有一個線程獲得鎖,對共用資源的所有訪問都需要首先獲得鎖。不過,某些鎖可能允許對共用資源並發訪問,如 ReadWriteLock 的讀取鎖。

synchronized 方法或語句的使用提供了對與每個對象相關的隱式監視器鎖的訪問,但卻強制所有鎖擷取和釋放均要出現在一個塊結構中:當擷取了多個鎖時,它們必須以相反的順序釋放,且必須在與所有鎖被擷取時相同的詞法範圍內釋放所有鎖。

雖然 synchronized 方法和語句的範圍機制使得使用監視器鎖編程方便了很多,而且還協助避免了很多涉及到鎖的常見編程錯誤,但有時也需要以更為靈活的方式使用鎖。例如,某些遍曆並發訪問的資料結果的演算法要求使用 "hand-over-hand" 或 "chain locking":擷取節點 A 的鎖,然後再擷取節點 B 的鎖,然後釋放 A 並擷取 C,然後釋放 B 並擷取 D,依此類推。Lock 介面的實現允許鎖在不同的作用範圍內擷取和釋放,並允許以任何順序擷取和釋放多個鎖,從而支援使用這種技術。

隨著靈活性的增加,也帶來了更多的責任。不使用塊結構鎖就失去了使用 synchronized 方法和語句時會出現的鎖自動釋放功能。在大多數情況下,應該使用以下語句:

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }
 鎖定和取消鎖定出現在不同作用範圍中時,必須謹慎地確保保持鎖定時所執行的所有代碼用 try-finally 或 try-catch 加以保護,以確保在必要時釋放鎖。
Lock 實現提供了使用 synchronized 方法和語句所沒有的其他功能,包括提供了一個非塊結構的擷取鎖嘗試 (tryLock())、一個擷取可中斷鎖的嘗試 (lockInterruptibly()) 和一個擷取逾時失效鎖的嘗試 (tryLock(long, TimeUnit))。

Lock 類還可以提供與隱式監視器鎖完全不同的行為和語義,如保證排序、非重入用法或死結檢測。如果某個實現提供了這樣特殊的語義,則該實現必須對這些語義加以記錄。

注意,Lock 執行個體只是普通的對象,其本身可以在 synchronized 語句中作為目標使用。擷取 Lock 執行個體的監視器鎖與調用該執行個體的任何 lock() 方法沒有特別的關係。為了避免混淆,建議除了在其自身的實現中之外,決不要以這種方式使用 Lock 執行個體。

除非另有說明,否則為任何參數傳遞 null 值都將導致拋出 NullPointerException。

記憶體同步
所有 Lock 實現都必須 實施與內建監視器鎖提供的相同記憶體同步語義,如 The Java Language Specification, Third Edition (17.4 Memory Model) 中所描述的:

成功的 lock 操作與成功的 Lock 操作具有同樣的記憶體同步效應。
成功的 unlock 操作與成功的 Unlock 操作具有同樣的記憶體同步效應。
不成功的鎖定與取消鎖定操作以及重入鎖定/取消鎖定操作都不需要任何記憶體同步效果。
實現注意事項
三種形式的鎖擷取(可中斷、不可中斷和定時)在其效能特徵、排序保證或其他實現品質上可能會有所不同。而且,對於給定的 Lock 類,可能沒有中斷進行中的 鎖擷取的能力。因此,並不要求實現為所有三種形式的鎖擷取定義相同的保證或語義,也不要求其支援中斷進行中的鎖擷取。實現必需清楚地對每個鎖定方法所提供的語義和保證進行記錄。還必須遵守此介面中定義的中斷語義,以便為鎖擷取中斷提供支援:完全支援中斷,或僅在進入方法時支援中斷。

由於中斷通常意味著取消,而通常又很少進行中斷檢查,因此,相對於普通方法返回而言,實現可能更喜歡響應某個中斷。即使出現在另一個操作後的中斷可能會釋放線程鎖時也是如此。實現應記錄此行為

File: Professor.java

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Version;

@Entity
public class Professor {
    @Id private int id;
    private String name;
    private long salary;
    private int vacationDays;
    @Version private int version;
    @ManyToOne(cascade={CascadeType.REFRESH})
    private Professor manager;
   

    public int getId() {
        return id;
    }
   
    public void setId(int id) {
        this.id = id;
    }
   
    public String getName() {
        return name;
    }
   
    public void setName(String name) {
        this.name = name;
    }
   
    public long getSalary() {
        return salary;
    }
   
    public void setSalary(long salary) {
        this.salary = salary;
    }
   
    public int getVacationDays() {
        return vacationDays;
    }

    public void setVacationDays(int vacation) {
        this.vacationDays = vacation;
    }

   
    public Professor getManager() {
        return manager;
    }
   
    public void setManager(Professor manager) {
        this.manager = manager;
    }

    public String toString() {
        return "Professor id: " + getId() + " name: " + getName() +
               " vacation: " + getVacationDays() + " salary: " + getSalary();
    }
}


File: ProfessorService.java

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.Query;

public class ProfessorService {
  protected EntityManager em;

  public ProfessorService(EntityManager em) {
    this.em = em;
  }


  public void lockAllProfessors() {
    Query query = em.createQuery("SELECT e FROM Professor e");
   
    for(Object employee: query.getResultList()){
      em.lock(employee, LockModeType.WRITE);
    }
   
   
  }

}


File: JPAUtil.java

import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;

public class JPAUtil {
  Statement st;
 
  public JPAUtil() throws Exception{
    Class.forName("org.hsqldb.jdbcDriver");
    System.out.println("Driver Loaded.");
    String url = "jdbc:hsqldb:data/tutorial";

    Connection conn = DriverManager.getConnection(url, "sa", "");
    System.out.println("Got Connection.");
    st = conn.createStatement();
  }
  public void executeSQLCommand(String sql) throws Exception {
    st.executeUpdate(sql);
  }
  public void checkData(String sql) throws Exception {
    ResultSet rs = st.executeQuery(sql);
    ResultSetMetaData metadata = rs.getMetaData();

    for (int i = 0; i < metadata.getColumnCount(); i++) {
      System.out.print("t"+ metadata.getColumnLabel(i + 1));
    }
    System.out.println("n----------------------------------");

    while (rs.next()) {
      for (int i = 0; i < metadata.getColumnCount(); i++) {
        Object value = rs.getObject(i + 1);
        if (value == null) {
          System.out.print("t       ");
        } else {
          System.out.print("t"+value.toString().trim());
        }
      }
      System.out.println("");
    }
  }
}


File: Main.java

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {
  public static void main(String[] a) throws Exception {
    JPAUtil util = new JPAUtil();

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("ProfessorService");
    EntityManager em = emf.createEntityManager();
    ProfessorService service = new ProfessorService(em);

    em.getTransaction().begin();

    service.lockAllProfessors();

    util.checkData("select * from Professor");

    em.getTransaction().commit();
    em.close();
    emf.close();
  }
}

 

 


File: persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence" version="1.0">
  <persistence-unit name="JPAService" transaction-type="RESOURCE_LOCAL">
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.connection.password" value=""/>
      <property name="hibernate.connection.url" value="jdbc:hsqldb:data/tutorial"/>
    </properties>
  </persistence-unit>
</persistence>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.