程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 詳解Java多線程編程中的線程同步辦法

詳解Java多線程編程中的線程同步辦法

編輯:關於JAVA

詳解Java多線程編程中的線程同步辦法。本站提示廣大學習愛好者:(詳解Java多線程編程中的線程同步辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解Java多線程編程中的線程同步辦法正文


1、多線程的同步:
1.1、同步機制:
在多線程中,能夠有多個線程試圖拜訪一個無限的資本,必需預防這類情形的產生。所以引入了同步機制:在線程應用一個資本時為其加鎖,如許其他的線程便不克不及拜訪誰人資本了,直到解鎖後才可以拜訪。

1.2、同享成員變量的例子:
成員變量與部分變量:
成員變量:

假如一個變量是成員變量,那末多個線程對統一個對象的成員變量停止操作,這多個線程是同享一個成員變量的。

部分變量:

假如一個變量是部分變量,那末多個線程對統一個對象停止操作,每一個線程都邑有一個該部分變量的拷貝。他們之間的部分變量互不影響。

上面舉例解釋:
完成了Runnable的線程類:

class MyThread3 implements Runnable{

 //兩個線程操作統一個對象,同享成員變量
 //int i;
 @Override
 public void run() {
  //兩個線程操作統一個對象,各自保留部分變量的拷貝
  int i = 0;
  while(i<100){
   System.out.println(i);
   i++;
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}

在main辦法頂用兩個線程操作統一個對象:

public static void main(String[] args) {

 MyThread3 myThread = new MyThread3();
 //上面兩個線程對統一個對象(Runnable的完成類對象)停止操作
 Thread thread = new Thread(myThread);
 Thread thread2 = new Thread(myThread);
 //各自保留部分變量的拷貝,互不影響,輸入200個數字
 thread.start();
 thread2.start();
}

這裡假如把i釀成成員變量,則輸入100個數字。

1.3、同享資本招致的讀取毛病
上面舉個例子,兩個線程共用一個Number對象,經由過程Number類的getNumber辦法獲得數據,讀取數據並改寫時,發明了反復讀操作:

起首創立一個Number類:

class Number{
 private int number = 10;
 public String getNumber(int i){
  if(number > 0){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   number -= i;
   return "掏出"+i+"勝利,殘剩數目:"+number;
  }
  return "掏出"+i+"掉敗,殘剩數目:"+number;
 }
}

線程類,在線程類中的公有屬性包括了Number類的援用:

class MyThread4 extends Thread{

 //兩個線程操作統一個對象,同享成員變量
 Number number;
 public MyThread4(Number number){
  this.number = number;
 }
 @Override
 public void run() {
  System.out.println(number.getNumber(8));
 }
}

在main函數中創立兩個線程類,包括了統一個Number類實例的援用:

public static void main(String[] args) {

 Number number = new Number();
 //兩個線程操作統一個對象,同享對象number的成員變量number
 MyThread4 myThread = new MyThread4(number);
 MyThread4 myThread2 = new MyThread4(number);
 myThread.start();
 myThread2.start();
}

如許,當第一個線程讀取Number中的number變量時先保留上去再休眠0.1秒,然後第二個線程再讀取number變量並保留,此時兩個線程保留了異樣的數字,在修正時,也就招致修正了統一個數字兩次。

2、同步機制的完成:

在多線程並發編程中Synchronized一向是元老級腳色,許多人都邑稱謂它為分量級鎖,然則跟著Java SE1.6對Synchronized停止了各類優化以後,有些情形下它其實不那末重了”
Java中的每個對象都可以作為鎖。

關於同步辦法,鎖是以後實例對象。
關於靜態同步辦法,鎖是以後對象的Class對象。
關於同步辦法塊,鎖是Synchonized括號裡設置裝備擺設的對象。
當一個線程試圖拜訪同步代碼塊時,它起首必需獲得鎖,加入或拋出異常時必需釋放鎖。
2.1、應用synchronized症結字創立synchronized辦法:
應用synchronized症結字,該症結字潤飾的辦法叫做同步辦法。

Java中每一個對象都有一個鎖或許稱為監督器,當拜訪某個對象的synchronized辦法時,表現將該對象上鎖,而不只僅是為該辦法上鎖。

如許假如一個對象的synchronized辦法被某個線程履行時,其他線程沒法拜訪該對象的任何synchronized辦法(然則可以挪用其他非synchronized的辦法)。直至該synchronized辦法履行完。

靜態的synchronized辦法挪用情形:
當挪用一個對象的靜態synchronized辦法時,它鎖定的其實不是synchronized辦法地點的對象,而是synchronized辦法地點對象對應的Class對象。如許,其他線程就不克不及挪用該類的其他靜態synchronized辦法了,然則可以挪用非靜態的synchronized辦法。

結論:履行靜態synchronized辦法鎖辦法地點對象,履行非靜態synchronized辦法鎖辦法地點對象對應的Class對象。

上面是多線程挪用靜態的辦法的例子,因為鎖定了辦法地點對象對應的Class對象,其他線程沒法挪用該辦法地點對象其他的靜態synchronized辦法:

/**
 * 界說一個類,包括了線程類須要挪用的辦法
 */
class Compute1{
 //這時候假如某個線程挪用該辦法,
 //將鎖定synchronized辦法地點對象對應的class對象,
 //而不是鎖定synchronized辦法地點對象
 public synchronized static void execute(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute1 " + i++);
  }
 }
 public synchronized static void execute2(){
  for(int i = 0; i<100; i++){
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("compute1:execute2 " + i++);
  }
 }
}

main辦法中兩個線程分離挪用統一個對象的兩個static synchronized辦法:

public static void main(String[] args) {
 Compute1 com = new Compute1();
 Thread thread1 = new Thread1(com);
 Thread thread2 = new Thread2(com);
 thread1.start();
 thread2.start();
}

一次只能挪用一個靜態辦法,直到履行完成。

2.2、應用synchronized創立同步代碼塊:
經由過程應用synchronized同步代碼塊,鎖定一個對象,該對象作為可履行的標記從而到達同步的後果:

/**
 * 界說一個類,包括了線程類須要挪用的辦法
 */
class Compute1{
 //經由過程同步代碼塊鎖定object1對象停止鎖定了其他異樣的synchronized代碼塊
 private Object object1 = new Object();
 public void execute(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute1 " + i++);
   }
  }

 }
 public synchronized void execute2(){
  synchronized(object1){
   for(int i = 0; i<100; i++){
    try {
     Thread.sleep(100);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    System.out.println("compute1:execute2 " + i++);
   }
  }
 }
}

假如想要應用synchronized同步代碼塊到達和應用synchronized辦法異樣的後果,可以鎖定this援用:

synchronized(this){
 …
}

2.3、synchronized辦法和synchronized同步代碼塊的差別:
synchronized同步代碼塊只是鎖定了該代碼塊,代碼塊裡面的代碼照樣可以被拜訪的。

synchronized辦法是粗粒度的並發掌握,某一個時辰只能有一個線程履行該synchronized辦法。

synchronized同步代碼塊是細粒度的並發掌握,只會將塊中的代碼同步,代碼塊以外的代碼可以被其他線程同時拜訪。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved