简体   繁体   English

如果一个同步方法调用另一个非同步方法,非同步方法是否有锁

[英]If a synchronized method calls another non-synchronized method, is there a lock on the non-synchronized method

In Java, if a synchronized method contains a call to a non-synchronized, can another method still access the non-synchronized method at the same time?在 Java 中,如果同步方法包含对非同步方法的调用,那么另一个方法是否仍然可以同时访问非同步方法? Basically what I'm asking is everything in the synchronized method have a lock on it (including calls to other synchronized methods)?基本上我要问的是同步方法中的所有内容都对其进行了锁定(包括对其他同步方法的调用)?

If a synchronized method calls another non-synchronized method, is there a lock on the non-synchronized method如果一个同步方法调用另一个非同步方法,非同步方法是否有锁

The answer depends on the context.答案取决于上下文。

If you are in a synchronized method for an object, then calls by other threads to other methods of the same object instance that are also synchronized are locked.如果你是在一个synchronized的对象的方法,然后通过其他线程对同一个对象实例也在其他方法调用synchronized被锁定。 However calls by other threads to non-synchronized methods are not locked – anyone can call them at the same time.然而,其他线程对非同步方法的调用不会被锁定——任何人都可以同时调用它们。

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() {
   ...
}

Also, if you call someSynchronizedMethod() but happen to be within the someNonSynchronizedMethod() method, you still hold the lock.此外,如果您调用someSynchronizedMethod()但碰巧在someNonSynchronizedMethod()方法中,您仍然持有锁。 The lock is enabled when you enter a synchronized method (or block) and is disabled when you exit that method.当您进入同步方法(或块)时该锁被启用,而当您退出该方法时该锁被禁用。 You can call all sorts of other unsynchronized methods and they will still be locked.您可以调用各种其他未同步的方法,它们仍将被锁定。

But you are asking two different things in your question:但是你在你的问题中问了两件不同的事情:

In Java, if a synchronized method contains a call to a non-synchronized, can another method still access the non-synchronized method at the same time?在 Java 中,如果同步方法包含对非同步方法的调用,那么另一个方法是否仍然可以同时访问非同步方法?

Yes.是的。 Other methods can access non-synchronized methods.其他方法可以访问非同步方法。

Basically what I'm asking is everything in the synchronized method have a lock on it (including calls to other synchronized methods)?基本上我要问的是同步方法中的所有内容都对其进行了锁定(包括对其他同步方法的调用)?

Uh, yes.嗯,是的。 Other calls to synchronized methods are locked.其他对同步方法的调用被锁定。 But non-synchronized methods are not locked.但是非同步方法不会被锁定。

Also, remember that if the method is static then the lock is on the Class object in the ClassLoader .另外,请记住,如果该方法是static那么锁位于ClassLoaderClass对象上。

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

If the method is an instance method then the lock is on the instance of the class.如果方法是一个实例方法,那么锁就在类的实例上。

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

There are 2 different locks in those 2 cases.在这两种情况下有两种不同的锁。

Lastly, when you are dealing with synchronized instance methods, each instance of the class is what is locked.最后,当您处理synchronized实例方法时,类的每个实例都是被锁定的。 This means that two threads could be in the same synchronized method at the same time with different instances .这意味着两个线程可以同时使用不同的实例在同一个synchronized方法中。 But if 2 threads try to operate on synchronized methods on the same instance, one will block until the other one exits the method.但是如果 2 个线程尝试在同一个实例上操作synchronized方法,一个线程将阻塞,直到另一个线程退出该方法。

If thread A calls synchronized method M1 which in turn calls unsynchronized method M2, then thread B can still call M2 without blocking.如果线程 A 调用同步方法 M1,而后者又调用非同步方法 M2,则线程 B 仍然可以调用 M2 而不会阻塞。

Synchronized method acquires and releases intrinsic lock on the object on which it is called.同步方法在调用它的对象上获取和释放内在锁。 This is why it may block.这就是它可能阻塞的原因。 Unsynchronized method doesn't attempt to acquire any lock (unless it is done explicitly in the code).非同步方法不会尝试获取任何锁(除非它在代码中明确完成)。

Thus, if you need to ensure mutual exclusion for M2 as well, you should make it synchronized regardless of whether its callers (like M1) are synchronized or not.因此,如果您还需要确保 M2 的互斥,则无论其调用者(如 M1)是否同步,都应使其同步。

The lock doesn't belong to the thread.锁不属于线程。 The lock actually belongs to the object(or Class in case of Class level lock), and a thread acquires lock on the Object(or Class in case of Class level lock) within a synchronized context.锁实际上属于对象(或类级别锁的类),线程在同步上下文中获取对象(或类级别锁的情况下的类)上的锁。 Now, there is no lock propagation in java as it is discussed above.现在,正如上面讨论的那样,java 中没有锁传播。 Here is a small demo:这是一个小演示:

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

    }
}
public class ThreadCreator1 implements 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 class 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();
        }
    }

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

}

Just I have used Reentrant lock here.只是我在这里使用了可重入锁。 If the above code is run, then there will be interleaving between thread 1 and thread 3, but if the lock portion of Task2 class is uncommented, then there will be no interleaving and the thread which acquire the lock first will complete fully first, then it will release the lock and then the other thread can carry on.如果上面的代码运行,那么线程1和线程3之间会有交错,但是如果Task2类的锁部分没有被注释掉,那么就不会有交错,先获取锁的线程会先完全完成,然后它将释放锁,然后另一个线程可以继续。

The lock belongs to the thread , not to the method (or more precisely, its stack frame).锁属于线程,而不属于方法(或更准确地说,属于它的堆栈框架)。 It just so happens that if you have a synchronized method, you're guaranteed that the thread will own the lock before the body of the method start, and will release it afterwards.碰巧的是,如果你有一个同步方法,你可以保证线程在方法体开始之前拥有锁,然后将释放它。

Another thread can still invoke the second, non-synchronized method.另一个线程仍然可以调用第二个非同步方法。 An unsynchronized method can be called by any thread at any time.任何线程都可以随时调用未同步的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM