Java EE陷阱#1:忽略@Singleton的默认锁定
EJB Singleton Bean是EJB 3.1規范引入的,通常用于存儲緩存的數據。 這意味著,我們嘗試通過使用Singleton來提高應用程序的性能。 總的來說,這很好。 特別是在并行調用不多的情況下。 但是,如果我們忽略默認鎖,并且并行調用的數量增加,它就會改變。
合理的默認值
讓我們從一些Java代碼開始,看看如何合理設置鎖。 以下代碼片段顯示了一個簡單的帶有計數器和兩個方法的EJB Singleton。 method1將計數器的當前值寫入日志,method2的計數從0到100。
@Singleton @Remote(SingletonRemote.class) public class DefaultLock implements SingletonRemote {Logger logger = Logger.getLogger(DefaultLock.class.getName());private int counter = 0;@Overridepublic void method1() {this.logger.info("method1: " + counter);}@Overridepublic void method2() throws Exception {this.logger.info("start method2");for (int i = 0; i < 100; i++) {counter++;logger.info("" + counter);}this.logger.info("end method2");} }如您所見,沒有定義鎖。 如果我們同時調用兩個方法,您希望在日志文件中看到什么?
2014-06-24 21:18:51,948 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 5) method1: 0 2014-06-24 21:18:51,949 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) start method2 2014-06-24 21:18:51,949 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 1 2014-06-24 21:18:51,949 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 2 2014-06-24 21:18:51,950 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 3... 2014-06-24 21:18:51,977 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 99 2014-06-24 21:18:51,977 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) 100 2014-06-24 21:18:51,978 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 4) end method2 2014-06-24 21:18:51,978 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 6) method1: 100 2014-06-24 21:18:51,981 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 7) method1: 100 2014-06-24 21:18:51,985 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 8) method1: 100 2014-06-24 21:18:51,988 INFO [blog.thoughts.on.java.singleton.lock.DefaultLock] (EJB default - 9) method1: 100好的,這可能有點意外,默認是整個Singleton上的容器管理的寫鎖定。 這是一個很好的默認設置,以避免同時修改屬性。 但是,如果我們要執行只讀操作,那么這是一個糟糕的默認設置。 在這種情況下,方法調用的序列化將導致高負載下較低的可伸縮性和較低的性能。
如何避免呢?
這個問題的答案很明顯,我們需要注意并發管理。 和Java EE中一樣,有兩種方法可以處理它。 我們可以自己做,也可以要求容器做。
Bean托管并發
我不想過多地討論Bean管理的并發性。 這是管理并發訪問的最靈活的方法。 容器允許并發訪問Singleton的所有方法,并且您必須根據需要保護其狀態。 這可以通過使用sync和volatile來完成。 但是要小心,很多時候這并不像看起來那樣容易。
容器管理并發
容器托管并發性更易于使用,但不如Bean托管方法靈活。 但是根據我的經驗,對于一般用例來說已經足夠了。
正如我們在日志中看到的那樣,容器管理的并發性是EJB Singleton的默認值。 容器為整個Singleton設置寫鎖定,并序列化所有方法調用。
我們可以更改此行為,并在方法和/或類級別上定義讀寫鎖。 這可以通過使用@ javax.ejb.Lock(javax.ejb.LockType)注釋Singleton類或方法來完成。 LockType枚舉提供值WRITE和READ來定義互斥寫鎖定或讀鎖定。
以下代碼片段顯示了如何將method1和method2的Lock設置為LockType.READ 。
@Singleton @Remote(SingletonRemote.class) public class ReadLock implements SingletonRemote {Logger logger = Logger.getLogger(ReadLock.class.getName());private int counter = 0;@Override@Lock(LockType.READ)public void method1() {this.logger.info("method1: " + counter);}@Override@Lock(LockType.READ)public void method2() throws Exception {this.logger.info("start method2");for (int i = 0; i < 100; i++) {counter++;logger.info("" + counter);}this.logger.info("end method2");} }如前所述,我們可以通過使用@Lock(LockType.READ)注釋類而不是同時使用這兩種方法來實現相同的目的。
好的,如果一切都按預期進行,則應該并行訪問這兩種方法。 因此,讓我們看一下日志文件。
2014-06-24 21:47:13,290 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 10) method1: 0 2014-06-24 21:47:13,291 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) start method2 2014-06-24 21:47:13,291 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 1 2014-06-24 21:47:13,291 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 2 2014-06-24 21:47:13,291 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 3... 2014-06-24 21:47:13,306 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 68 2014-06-24 21:47:13,307 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 69 2014-06-24 21:47:13,308 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 3) method1: 69 2014-06-24 21:47:13,310 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 70 2014-06-24 21:47:13,310 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 71... 2014-06-24 21:47:13,311 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 76 2014-06-24 21:47:13,311 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 77 2014-06-24 21:47:13,312 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 2) method1: 77 2014-06-24 21:47:13,312 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 78 2014-06-24 21:47:13,312 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 79... 2014-06-24 21:47:13,313 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 83 2014-06-24 21:47:13,313 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 84 2014-06-24 21:47:13,314 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 5) method1: 84 2014-06-24 21:47:13,316 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 85 2014-06-24 21:47:13,316 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 86 2014-06-24 21:47:13,317 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 87 2014-06-24 21:47:13,318 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 88 2014-06-24 21:47:13,318 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 6) method1: 89 2014-06-24 21:47:13,318 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 89 2014-06-24 21:47:13,319 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 90... 2014-06-24 21:47:13,321 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 99 2014-06-24 21:47:13,321 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) 100 2014-06-24 21:47:13,321 INFO [blog.thoughts.on.java.singleton.lock.ReadLock] (EJB default - 1) end method2結論
在本文開頭,我們發現Java EE使用容器管理的寫鎖作為默認值。 這導致所有方法調用的序列化處理,并降低了應用程序的可伸縮性和性能。 在實現EJB Singleton時,我們需要牢記這一點。
我們看了兩個用于控制并發管理的現有選項:Bean管理的并發和容器管理的并發。
我們使用容器托管方法為單例的這兩種方法定義了一個讀鎖。 這不像bean管理的方法那樣靈活,但是它更容易使用,并且在大多數情況下足夠了。 我們只需要提供一個注釋,容器將處理其余的注釋。
翻譯自: https://www.javacodegeeks.com/2014/06/java-ee-pitfalls-1-ignore-the-default-lock-of-a-singleton.html
總結
以上是生活随笔為你收集整理的Java EE陷阱#1:忽略@Singleton的默认锁定的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 固态硬盘安装方法电脑如何安装固态硬盘
- 下一篇: 早报:iPhone 15超大杯影像曝光