2012-03-01 2 views
25

В Java, если синхронизированный метод содержит вызов несинхронизированного, может ли другой метод по-прежнему обращаться к несинхронизированному методу в то же время? В основном, что я спрашиваю, все в синхронизированном методе имеет блокировку (включая вызовы для других синхронизированных методов)? Большое спасибоЕсли синхронизированный метод вызывает другой несинхронизированный метод, существует ли блокировка несинхронизированного метода

+2

Любые отзывы о моем ответе? Пожалуйста, примите это, если это поможет вам. – Gray

+0

Я думаю, что ответ Грея должен быть принят, поскольку он отвечает именно на то, что задают. – Sankalp

ответ

45

Если вы находитесь в методе synchronized, тогда звонки на другие методы, которые также являются другими потоками заблокированы. Однако вызовы несинхронизированных методов другими потоками - это , а не заблокировано - каждый может вызвать их одновременно.

public synchronized void someSynchronizedMethod() { 
    ... 
    someNonSynchronizedMethod(); 
    ... 
} 

// anyone can call this method even if the someSynchronizedMethod() method has 
// been called and the lock has been locked 
public void someNonSynchronizedMethod() { 
    ... 
} 

Кроме того, если вы звоните someSynchronizedMethod(), но случается в методе someNonSynchronizedMethod(), вы по-прежнему держать блокировку. Блокировка включена, когда вы вводите синхронизированный блок и отключается при выходе из этого метода. Вы можете вызывать всевозможные другие несинхронизированные методы, и они все равно будут заблокированы.

Но вы просите разные вещи в вашем вопросе:

В Java, если синхронизированный метод содержит вызов к несинхронизированному, может другой способ получить доступ к несинхронизированному методу в том же время?

Да. Другие методы могут получить доступ к несинхронизированным методам.

В принципе, я спрашиваю, есть ли у всего синхронизированного метода блокировка (включая вызовы другим синхронизированным методам)?

Э-э, да. Другие звонки на синхронизированы методы заблокированы. Но несинхронизированные методы не заблокированы.

Кроме того, помните, что если метод static, то замок находится на объекте Class в ClassLoader.

// this locks on the Class object in the ClassLoader 
public static synchronized void someStaticMethod() { 

Если метод является методом экземпляра, то блокировка находится на экземпляре класса.

// this locks on the instance object that contains the method 
public synchronized void someInstanceMethod() { 

В этих 2 случаях есть 2 разных замка.

Наконец, когда вы имеете дело с synchronized методами экземпляра, каждый экземпляр класса - это то, что заблокировано. Это означает, что два потока могут быть в одном методе synchronized одновременно с различными экземплярами. Но если 2 потока пытаются работать с методами synchronized в одном экземпляре, каждый будет блокироваться до тех пор, пока другой не выйдет из этого метода.

+0

Итак, я думаю, было бы неплохо вызвать несинхронизированные методы в синхронизированных ... потому что они могут быть вызваны одновременно другим методом. – dido

+3

Если это вызывает 2 потока для доступа к данным, которые необходимо синхронизировать, то да, это не очень хорошая идея. Однако это происходит постоянно с помощью 'toString()' и других методов. Это зависит только от вашего объекта и прецедента. – Gray

+1

Я хотел бы просто добавить сюда, что синхронный метод можно вызывать одновременно любое количество раз, если он вызывается на разные объекты. Блокировка применяется к конкретному объекту - экземпляру класса - если этот метод не является статическим. Я думаю, что это легко забыть, поскольку многие люди (включая все текущие плакаты) говорят о блокировке метода, как если бы он применялся независимо от экземпляра объекта. – arcy

2

Если поток A вызывает синхронизированный метод M1, который, в свою очередь, вызывает несинхронизированный метод M2, тогда поток B все равно может вызывать M2 без блокировки.

Синхронный метод получает и освобождает встроенную блокировку объекта, на который он вызывается. Вот почему он может блокироваться. Несинхронизированный метод не пытается получить блокировку (если это явно не указано в коде).

Таким образом, если вам необходимо обеспечить взаимное исключение для M2, вы должны синхронизировать его независимо от того, синхронизированы ли его вызывающие абоненты (например, M1) или нет.

0

Блокировка относится к резьбе , а не к методу (точнее, к его раме стека). Так получилось, что если у вас есть синхронизированный метод, вам гарантируется, что поток будет владеть блокировкой до начала запуска метода, и затем выпустит его.

Другой поток может вызывать второй несинхронизированный метод. Несинхронизированный метод может быть вызван любым потоком в любое время.

2

Замок не относится к нити. Блокировка фактически принадлежит объекту (или классу в случае блокировки уровня класса), и поток получает блокировку объекта (или класса в случае блокировки уровня класса) в синхронном контексте. Теперь в java нет распространения блокировки, как описано выше. Вот небольшая демонстрация:

общественного класса TestThread {

/** 
* @param args 
* @throws InterruptedException 
*/ 
public static void main(String[] args) throws InterruptedException { 
    // TODO Auto-generated method stub 
    ThreadCreator1 threadCreator1 = new ThreadCreator1(); 
    ThreadCreator2 threadCreator2 = new ThreadCreator2(); 

    Thread t1 = new Thread(threadCreator1,"Thread 1"); 
    Thread t3 = new Thread(threadCreator1,"Thread 3"); 
    Thread t2 = new Thread(threadCreator2,"Thread 2"); 

    t1.start(); 
    Thread.sleep(2000); 
    t3.start(); 

} 

}

общественного класса ThreadCreator1 реализует Runnable {

private static final Task task= new Task(); 
private static final Task2 task2= new Task2(); 

@Override 

public void run() { 

    try { 

     if(Thread.currentThread().getName().equals("Thread 1")) 
      task.startTask2(task2); 
     if(Thread.currentThread().getName().equals("Thread 3")) 
      task2.startTask(); 

    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    // TODO Auto-generated method stub 

    /**/ 

    } 
} 

общественного класса Task {

public static final Task task = new Task(); 
public static List<String> dataList = new ArrayList<String>(); 
ReentrantLock lock = new ReentrantLock(); 



public void startTask2(Task2 task2) throws InterruptedException 
{ 

    try{ 

     lock.lock(); 
     //new Task2().startTask(); 
     task2.startTask(); 
    } 
    catch(Exception e) 
    { 

    } 
    finally{ 
     lock.unlock(); 
    } 
} 

}

общественного класса Task2 {

ReentrantLock lock = new ReentrantLock(); 
public void startTask() throws InterruptedException 
{ 

    try{ 
     //lock.lock(); 
     for(int i =0 ;i< 10;i++) 
    { 
     System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName()); 
     Thread.sleep(1000); 
    } 
    } 
    catch(Exception e) 
    { 

    } 
    /*finally 
    { 
     lock.unlock(); 
    }*/ 
} 

}

Просто я использовал повторно входимый запирать здесь. Если приведенный выше код запущен, то между потоком 1 и потоком 3 будет чередоваться, но если часть блокировки класса Task2 раскоментирована, тогда не будет чередования, и поток, который сначала получит блокировку, полностью завершит, то он освободит замок, а затем другой поток может продолжить.

Смежные вопросы