1. 程式人生 > >多執行緒下synchronized修飾static方法與非static方法的區別

多執行緒下synchronized修飾static方法與非static方法的區別

一直對多執行緒的概念比較模糊,今天就寫了個關於變數原子操作的小程式,好讓自己加深一下理解

程式碼如下:

 

 
  1. package atomic;

  2.  
  3. public class JoinThread extends Thread {

  4.  
  5. public static int i = 0;

  6.  
  7. //public static AtomicInteger atomicInteger = new AtomicInteger(0);

  8.  
  9. public synchronized void inc(){

  10. i ++;

  11. }

  12. @Override

  13. public void run() {

  14. for (int x = 0; x < 10; x++) {

  15. inc();

  16. try {

  17. Thread.sleep(33);

  18. } catch (InterruptedException e) {

  19. e.printStackTrace();

  20. }

  21. }

  22. }

  23.  
  24. public static void main(String[] args) throws InterruptedException {

  25. // TODO Auto-generated method stub

  26. // JoinThread jt = new JoinThread();

  27. Thread[] t = new Thread[100];

  28. for (int i = 0; i < t.length; i++) {

  29. t[i] = new JoinThread();

  30. }

  31. for (int i = 0; i < t.length; i++) {

  32. t[i].start();

  33. }

  34. for (int i = 0; i < t.length; i++) {

  35. t[i].join();

  36. }

  37. System.out.println(JoinThread.i);

  38. }

  39.  
  40. }


執行完發現,i並沒有如想像中的輸出1000,即使i新增volatile進行修飾,也不會輸出1000,值是隨機變化的。

 

將inc()方法新增static修飾,結果無問題,準確無誤的輸出1000。

 

另外一種改法,將程式碼改成:

 

 
  1. Thread[] t = new Thread[100];

  2. for (int i = 0; i < t.length; i++) {

  3. t[i] = new JoinThread();

  4. }

修改成:

 

 
  1. JoinThread jt = new JoinThread();

  2. Thread[] t = new Thread[100];

  3. for (int i = 0; i < t.length; i++) {

  4. t[i] = new Thread(jt);

  5. }

結果無問題,準確無誤的輸出1000

 

這裡主要涉及到類物件(static方法),物件方法(非static方法)

我們知道,當synchronized修飾一個static方法時,多執行緒下,獲取的是類鎖(即Class本身,注意:不是例項);

當synchronized修飾一個非static方法時,多執行緒下,獲取的是物件鎖(即類的例項物件)

所以,當synchronized修飾一個static方法時,建立執行緒不管是new JoinThread()還是new Thread(new JoinThread()),在run方法中執行inc()方法都是同步的;

相反,當synchronized修飾一個非static方法時,如果用new JoinThread()還是new Thread(new JoinThread())方式建立執行緒,就無法保證同步操作,因為這時

inc()是屬於物件方法,每個執行緒都執有一個獨立的物件例項new JoinThread(),所以多執行緒下執行inc()方法並不會產生互斥,也不會有同步操作。

 

另外如果考慮到變更的原子操作,可使用atomic包下面的包裝物件,這些物件都是對volatile修飾變數的一種延伸,可保證變數的原子操作而不用去同步方法或

程式碼塊是否同步。