熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

淺談Java多線程的同步問題

2013-11-23 19:46:33  來源: Java高級技術 

  多線程的同步依靠的是對象鎖機制synchronized關鍵字的背後就是利用了封鎖來實現對共享資源的互斥訪問

  下面以一個簡單的實例來進行對比分析實例要完成的工作非常簡單就是創建個線程每個線程都打印從個數字我們希望線程之間不會出現交叉亂序打印而是順序地打印

  先來看第一段代碼這裡我們在run()方法中加入了synchronized關鍵字希望能對run方法進行互斥訪問但結果並不如我們希望那樣這是因為這裡synchronized鎖住的是this對象即當前運行線程對象本身代碼中創建了個線程而每個線程都持有this對象的對象鎖這不能實現線程的同步

  代碼
    package comvista;
    class MyThread implements javalangRunnable {
     private int threadId;

  public MyThread(int id) {
      thisthreadId = id;
     }

  @Override
     public synchronized void run() {
      for (int i = ; i < ; ++i) {
       Systemoutprintln(Thread ID: + thisthreadId + : + i);
      }
     }
    }

  public class ThreadDemo {
     /**
      * @param args
      * @throws InterruptedException
      */
     public static void main(String[] args) throws InterruptedException {
      for (int i = ; i < ; ++i) {
       new Thread(new MyThread(i))start();
       Threadsleep();
      }
     }
    }

  從上述代碼段可以得知要想實現線程的同步則這些線程必須去競爭一個唯一的共享的對象鎖

  基於這種思想我們將第一段代碼修改如下所示在創建啟動線程之前先創建一個線程之間競爭使用的Object對象然後將這個Object對象的引用傳遞給每一個線程對象的lock成員變量這樣一來每個線程的lock成員都指向同一個Object對象我們在run方法中對lock對象使用synchronzied塊進行局部封鎖這樣就可以讓線程去競爭這個唯一的共享的對象鎖從而實現同步

  代碼
    package comvista;

  class MyThread implements javalangRunnable {
     private int threadId;
     private Object lock;

  public MyThread(int id Object obj) {
      thisthreadId = id;
      thislock = obj;
     }

  @Override
     public void run() {
      synchronized (lock) {
       for (int i = ; i < ; ++i) {
        Systemoutprintln(Thread ID: + thisthreadId + : + i);
       }
      }
     }
    }

  public class ThreadDemo {
     /**
      * @param args
      * @throws InterruptedException
      */
     public static void main(String[] args) throws InterruptedException {
      Object obj = new Object();
      for (int i = ; i < ; ++i) {
       new Thread(new MyThread(i obj))start();
       Threadsleep();
      }
     }
    }

  從第二段代碼可知同步的關鍵是多個線程對象競爭同一個共享資源即可上面的代碼中是通過外部創建共享資源然後傳遞到線程中來實現我們也可以利用類成員變量被所有類的實例所共享這一特性因此可以將lock用靜態成員對象來實現代碼如下所示

  代碼
    package comvista;

  class MyThread implements javalangRunnable {
     private int threadId;
     private static Object lock = new Object();

  public MyThread(int id) {
      thisthreadId = id;
     }

  @Override
     public void run() {
      synchronized (lock) {
       for (int i = ; i < ; ++i) {
        Systemoutprintln(Thread ID: + thisthreadId + : + i);
       }
      }
     }
    }

  public class ThreadDemo {
     /**
      * @param args
      * @throws InterruptedException
      */
     public static void main(String[] args) throws InterruptedException {
      for (int i = ; i < ; ++i) {
       new Thread(new MyThread(i))start();
       Threadsleep();
      }
     }
    }

  再來看第一段代碼實例方法中加入sychronized關鍵字封鎖的是this對象本身而在靜態方法中加入sychronized關鍵字封鎖的就是類本身靜態方法是所有類實例對象所共享的因此線程對象在訪問此靜態方法時是互斥訪問的從而可以實現線程的同步代碼如下所示

  代碼
    package comvista;

  class MyThread implements javalangRunnable {
     private int threadId;

  public MyThread(int id) {
      thisthreadId = id;
     }

  @Override
     public void run() {
      taskHandler(thisthreadId);
     }

  private static synchronized void taskHandler(int threadId) {
      for (int i = ; i < ; ++i) {
       Systemoutprintln(Thread ID: + threadId + : + i);
      }
     }
    }

  public class ThreadDemo {
     /**
      * @param args
      * @throws InterruptedException
      */
     public static void main(String[] args) throws InterruptedException {
      for (int i = ; i < ; ++i) {
       new Thread(new MyThread(i))start();
       Threadsleep();
      }
     }
    }


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27441.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.