Java 中同一个类中不同的 synchronized 办法不能够并发执行
多个线程拜访同一个类的 synchronized 办法时, 都是串行执行的 ! 就算有多个 cpu 也不例外 !
synchronized 办法应用了类 java 的内置锁, 即锁住的是办法所属对象自身. 同一个锁某个时刻只能被一个执行线程所获取, 因而其余线程都得期待锁的开释.
因而就算你有多余的 cpu 能够执行, 然而你没有锁, 所以你还是不能进入 synchronized 办法执行, CPU 因而而闲暇.
如果某个线程长期持有一个竞争强烈的锁, 那么将导致其余线程都因期待所的开释而被挂起, 从而导致 CPU 无奈失去利用, 零碎吞吐量低下. 因而要尽量避免某个线程对锁的长期占有 !
验证代码
public class SyncMethod {public synchronized void syncMethod2() {
try {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
}
public synchronized void syncMethod1() {System.out.println("######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)");
}
static class Thread1 extends Thread {
SyncMethod syncMethod;
public Thread1(SyncMethod syncMethod) {this.syncMethod = syncMethod;}
@Override
public void run() {syncMethod.syncMethod2();
}
}
static class Thread2 extends Thread {
SyncMethod syncMethod;
public Thread2(SyncMethod syncMethod) {this.syncMethod = syncMethod;}
@Override
public void run() {System.out.println("Thread2 running ...");
syncMethod.syncMethod1();}
}
public static void main(String[] args) throws InterruptedException {SyncMethod syncMethod = new SyncMethod();
Thread1 thread1 = new Thread1(syncMethod);
Thread2 thread2 = new Thread2(syncMethod);
thread1.start(); // 先执行, 以便抢占锁
Thread.sleep(500); // 放弃 cpu, 让 thread1 执行, 以便获的锁
thread2.start(); // 在 syncMethod1()办法取得锁时, 看看 syncMethod2()办法是否执行
/*
是否并发执行同一个对象不同的 synchronized 办法, 即看看是否同时进入一个对象 synchronized 办法块
1. 创立一个有两个 synchronized 办法的对象 `syncMethod`
2. 先启动一个线程 (Thread1), 并让其进入 syncMethod 对象的 sychronized 办法(syncMethod1) 内, 并使其停在 synchronized 办法内
3. 再启动一个线程(Thread2), 并执行 syncMethod 对象的一个 synchronized 办法(syncMethod2), 看看是否进入此办法内
输入如下:
@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)
Thread2 running ...
@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)
######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)
后果剖析:
察看显示, 在输入 `Thread2 running ...` 后会暂停数秒(Thread2 无奈取得所而被挂起, 因为锁曾经被 Thread1 持有).
如果不同线程能够同时拜访同一个对象不同 synchronized 办法的话,
在有足够 cpu 工夫片时(Thread1 在调用 syncMethod1 时应用 Thread.sleep 放弃了 cpu),
Thread2 调用的 syncMethod2 办法应该马上执行, 也就是 syncMethod2 办法中的语句在 `Thread2 running ...` 语句输入后马上输入,
而不是期待数秒才输入 (应为此时没有其余线程跟 Thread2 竞争 cpu, 况且当初的电脑都不只一个 cpu),
因而得出结论: "不同线程不能同时执行一个对象的不同 synchronized 办法"
其实此论断是不言而喻的, 原理后面曾经说明, 此处不再赘述.
*/
}
}
上面是一些对于应用锁的一些倡议:
①为了防止对锁的竞争, 你能够应用锁合成, 锁分段以及缩小线程持有锁的工夫
②如果上诉程序中的 syncMethod1 和 syncMethod2 办法是两个不相干的办法(申请的资源不存在关系),那么这两个办法能够别离应用两个不同的锁,革新之后 Thread1 和 Thread2 就不会产生因为锁竞争而挂起的状况了。革新后的 SyncMethod 类如下:
锁定两个不同的 Object 对象(lock1、lock2)
public class SyncMethod {private Object lock1 = new Object();
private Object lock2 = new Object();
public void syncMethod2() {synchronized (lock1) {
try {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
Thread.sleep(5000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
}
}
public void syncMethod1() {synchronized (lock2) {System.out.println("######################## (syncMethod1, 曾经获取内置锁 `SyncMethod.this`, 并行将退出)");
}
}
}
当然, 如果 syncMethod1 中耗时操作与锁定的资源无关, 那么也能够将耗时操作移出同步块. 在上述革新的根底上对 syncMethod1 的进一步革新如下:
public void syncMethod2() {synchronized (lock1) {System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 曾经获取内置锁 `SyncMethod.this`)");
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 行将开释内置锁 `SyncMethod.this`)");
}
// 将耗时操作移出同步块
try {Thread.sleep(5000);// 与同步应用的资源无关的耗时操作
} catch (InterruptedException e) {e.printStackTrace();
}
}