在Java中,如果同步方法包含对非同步的调用,是否还有另一种方法可以同时访问非同步方法?基本上我要问的是同步方法中的所有东西都锁定它(包括调用其他同步方法)?非常感谢
答案 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方法,你可以保证线程在方法体开始之前拥有锁,并在之后释放它。
另一个线程仍然可以调用第二个非同步方法。任何线程都可以随时调用非同步方法。