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