Java threads locking on a specific object

前端 未结 10 839
抹茶落季
抹茶落季 2020-12-12 00:06

I have a web application and I am using Oracle database and I have a method basically like this:

public static void saveSomethingImportantToDataBase(Object t         


        
相关标签:
10条回答
  • 2020-12-12 00:30

    If you can live with occasional over-synchronization (ie. work done sequentially when not needed) try this:

    1. Create a table with lock objects. The bigger table, the fewer chances for over-synchronizaton.
    2. Apply some hashing function to your id to compute table index. If your id is numeric, you can just use a remainder (modulo) function, if it is a String, use hashCode() and a remainder.
    3. Get a lock from the table and synchronize on it.

    An IdLock class:

    public class IdLock {
    
    private Object[] locks = new Object[10000];
    
    public IdLock() {
      for (int i = 0; i < locks.length; i++) {
        locks[i] = new Object();
      }
    }
    
    public Object getLock(int id) {
      int index = id % locks.length;
      return locks[index];
    }
    

    }

    and its use:

    private idLock = new IdLock();
    
    public void saveSomethingImportantToDataBase(Object theObjectIwantToSave) {
      synchronized (idLock.getLock(theObjectIwantToSave.getId())) {
        // synchronized work here
      }
    }
    
    0 讨论(0)
  • 2020-12-12 00:34

    synchronized keyword (or another sync operation) is must but is not enough for your problem. You should use a data structure to store which integer values are used. In our example HashSet is used. Do not forget clean too old record from hashset.

    private static HashSet <Integer>isUsed= new HashSet <Integer>();
    
    public synchronized static void saveSomethingImportantToDataBase(Object theObjectIwantToSave) {
    
          if(isUsed.contains(theObjectIwantToSave.your_integer_value) != null) {
    
          if (!methodThatChecksThatObjectAlreadyExists) {
             storemyObject() //pseudo code
          }
     // Have to do a lot other saving stuff, because it either saves everything or nothing
          commit() // pseudo code to actually commit all my changes to the database.
          isUsed.add(theObjectIwantToSave.your_integer_value);
    
      }
    }
    
    0 讨论(0)
  • 2020-12-12 00:36

    My opinion is you are not struggling with a real threading problem.

    You would be better off letting the DBMS automatically assign a non conflicting row id.

    If you need to work with existing row ids store them as thread local variables. If there is no need for shared data do not share data between threads.

    http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

    An Oracle dbms is much better in keeping the data consistent when an application server or a web container.

    "Many database systems automatically generate a unique key field when a row is inserted. Oracle Database provides the same functionality with the help of sequences and triggers. JDBC 3.0 introduces the retrieval of auto-generated keys feature that enables you to retrieve such generated values. In JDBC 3.0, the following interfaces are enhanced to support the retrieval of auto-generated keys feature ...."

    http://download.oracle.com/docs/cd/B19306_01/java.102/b14355/jdbcvers.htm#CHDEGDHJ

    0 讨论(0)
  • 2020-12-12 00:39

    To answer your question about locking the Integer, the short answer is NO - it won't prevent threads with another Integer instance with the same value from entering. The long answer: depends on how you obtain the Integer - by constructor, by reusing some instances or by valueOf (that uses some caching). Anyway, I wouldn't rely on it.

    A working solution that will work is to make the method synchronized:

    public static synchronized void saveSomethingImportantToDataBase(Object theObjectIwantToSave) {
        if (!methodThatChecksThatObjectAlreadyExists) {
            storemyObject() //pseudo code
        }
        // Have to do a lot other saving stuff, because it either saves everything or nothing
        commit() // pseudo code to actually commit all my changes to the database.
    }
    

    This is probably not the best solution performance-wise, but it is guaranteed to work (note, if you are not in a clustered environment) until you find a better solution.

    0 讨论(0)
提交回复
热议问题