我只是好奇,是否有线程T1说部分地执行同步块然后释放对象的锁定而另一个线程T2执行相同的块?像这样:
line1: synchronized(this){
line2: if(INSTANCE == null)
line3: INSTANCE = new Object(); //say a variable is initialized
line4: return INSTANCE;
line5: }
线程T1是否可能获取当前对象(this
)的锁并执行line1和line2。然后线程T1被线程T2抢占,T1释放锁定,T2获取this
上的锁定并执行相同的块(所有行1到5)。然后线程T1再次获取锁定并继续从第3行执行?
基本上,T1会将INSTANCE
视为空,因此T2将会创建一个新的对象。
如果不可能,有人可以解释原因吗?
附录:
感谢大家的回答。我的问题有点误导。我要问的是,一旦一个线程执行一个同步块,它可以在整个块执行之前释放锁(不是通过显式调用wait()
而是通过进程,CPU依赖的东西)?在JLS或JVM中是否有合同保证一旦线程开始执行同步块,对象的锁定直到块结束才会被释放?我的理解是同步保证没有2个线程可以同时执行块(或其他同步的方法/块),但锁是否保持到块到达块结束?它有点明显,但它是否在JLS中指定?
答案 0 :(得分:4)
线程抢占不会导致抢占的线程释放其锁定。如果确实如此,锁将毫无价值。 synchronized
块的重点是它将禁止其他线程在同一对象上同步,直到线程释放锁(通过离开synchronized
块)。
答案 1 :(得分:1)
即使线程被抢占,它也不会释放锁定。锁仍然存在。如果另一个线程出现,它将阻塞(停止运行)直到锁被释放,即使原始线程在释放锁之前被抢占了几次。基本上几乎任何类型的锁都会在堆中有一些存储空间,这些存储空间会被写入以指示存在锁定。它是永久性的,直到线程或系统写入不同的值来指示锁是空闲的。
当然可以编写允许访问实例或字段而无需锁定的代码,但这是编码错误。原始线程也可以提前退出块(比如抛出异常) - 这会释放锁定,其他线程可以正常继续。
答案 2 :(得分:0)
我很确定第二个线程在第一个线程执行整个块之前不可能进入synchronize
块。在获取对象的锁定时,将阻止尝试输入同步代码的所有其他线程。
在此处查看更多信息:http://tutorials.jenkov.com/java-concurrency/synchronized.html
答案 3 :(得分:-1)
基本上你可以使用Locks个对象。锁定对象可以允许您逐行顺序地应用和释放多个锁定上的锁定。
关于如何实施它的非常好的教程here
查看以下代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class test2{
private static Object instance = null;
private static test2 t = new test2();
private static Lock lock = new ReentrantLock();
public static void main(String[] args) {
A a = new A();
B b = new B();
a.setName("Thread-A");
b.setName("Thread-B");
a.start();
b.start();
}
public Object getObj(){
try {
lock.lock();
System.out.println("Begin Current thread: "+ Thread.currentThread().getName());
if(instance == null){
if(Thread.currentThread().getName().equalsIgnoreCase("Thread-A")){
lock.unlock();
while(instance==null){
System.out.println(Thread.currentThread().getName() +" : instance is null");
}
while(true){
if(!lock.tryLock()){
System.out.println(Thread.currentThread().getName() + " waiting for re lock");
}else{
lock.lock();
break;
}
}
}
instance =new Object();
System.out.println("End Current thread: "+ Thread.currentThread().getName());
if (((ReentrantLock) lock).isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
public static class A extends Thread{
@Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
public static class B extends Thread{
@Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
}
<强>输出强>
Begin Current thread: Thread-A
Thread-A : instance is null
Begin Current thread: Thread-B
Thread-A : instance is null
End Current thread: Thread-B
Thread-A waiting for re lock
End Current thread: Thread-A