如果synchronized方法调用另一个非同步方法,那么非同步方法是否存在锁定

时间:2012-03-01 23:34:30

标签: java multithreading methods locking synchronized

在Java中,如果同步方法包含对非同步的调用,是否还有另一种方法可以同时访问非同步方法?基本上我要问的是同步方法中的所有东西都锁定它(包括调用其他同步方法)?非常感谢

4 个答案:

答案 0 :(得分:55)

  

如果synchronized方法调用另一个非同步方法,那么非同步方法是否存在锁定

是和否。

如果您使用synchronized方法,则锁定其他线程同样为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中,如果同步方法包含对非同步的调用,是否还可以同时访问非同步方法?

是。其他方法可以访问非同步方法。

  

基本上我要问的是,synchronized方法中的所有内容都有锁(包括对其他同步方法的调用)?

呃,是的。对 synchronized 方法的其他调用被锁定。但是非同步方法没有被锁定。

此外,请记住,如果方法为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方法进行操作,则会阻塞一个,直到另一个退出该方法。

答案 1 :(得分:3)

如果线程A调用同步方法M1,后者又调用非同步方法M2,那么线程B仍可以不阻塞地调用M2。

Synchronized方法获取并释放调用它的对象的内部锁。这就是它可能阻止的原因。非同步方法不会尝试获取任何锁(除非在代码中明确完成)。

因此,如果您还需要确保M2的互斥,则无论其呼叫者(如M1)是否同步,都应使其同步。

答案 2 :(得分:2)

锁不属于该线程。锁实际上属于对象(或类级别锁定时的类),并且线程在同步上下文中获取对象(或类级别锁定时的类)的锁定。 现在,java中没有锁传播,如上所述。这是一个小型演示:

public class 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

    /**/

    }
}

公共课程任务{

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();
    }
}

}

public class 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();
    }*/
}

}

我在这里使用了Reentrant锁。 如果运行上面的代码,则线程1和线程3之间将存在交错,但如果取消注释Task2类的锁定部分,则不会进行交错,首先获取锁定的线程将首先完全完成,然后它将释放锁定,然后其他线程可以继续。

答案 3 :(得分:0)

锁属于线程,而不属于方法(或更准确地说,属于其堆栈帧)。碰巧的是,如果你有一个synchronized方法,你可以保证线程在方法体开始之前拥有锁,并在之后释放它。

另一个线程仍然可以调用第二个非同步方法。任何线程都可以随时调用非同步方法。