# 同步處理 Synchronized

synchronized 有「同步」的意思，在 Java 中 這個關鍵字可以使各執行緒在時間上做協調，\
即 一次只允許一個執行緒進行處理，而其他的執行緒必須等待上個執行緒處理完後才可以進入處理。

當數個執行緒同時啟動，而且還共用同個變數，就會常發生無法發覺的錯誤。

## 範例題目

例如一個需要計算累加金額的變數 sum，但有兩個執行緒 p1 與 p2 同時共用。

參考以下範例：

慈善捐款接受捐款，而每次會計算出總捐款額(sum)。\
今日有兩位善心人士(p1,p2)，兩人每天(1次)都會捐100元，連續三天過後 總捐款額若無他人捐款，\
那麼總額會是600元。

因應網路塞車等因素：可以加上睡眠，當每接受一次的捐款時，小睡0\~1秒。

### 完整程式碼(未經同步處理)

讓我們先瞧瞧 沒有經過同步處理的程式：

```
class CDonate
{
   private static int sum=0;
   public static void add(int n)
   {
      int tmp=sum;
      tmp=tmp+n;
      try
      {
         Thread.sleep((int)(1000*Math.random()));
      }
      catch(InterruptedException e){}
      sum=tmp;
      System.out.println("捐款總額= "+sum);
  }
}
class CPerson extends Thread
{
   public void run()
   {
      for(int i=1;i<=3;i++)
         CDonate.add(100);
   }
}
public class synchronized_1
{
   public static void main(String args[])
   {
      CPerson p1=new CPerson();
      CPerson p2=new CPerson();
      p1.start();
      p2.start();
   }
}
```

當我們執行結果後，會發現執行結果跟預期的不同：

![](/files/-MPaP0mKtCIr2orPE-Hv)

捐款總額竟然只是300，應該要是600呀？

原來在處理p1執行緒還未結束時，p2也開始進入add()當中，因此造成計算錯誤。\
但透過加上 synchronized 關鍵字後，又會有怎樣的效果呢？

在 add() 加上synchronized 關鍵字

```
public synchronized static void add(int n){}
```

神奇的事情，發生了！！\
執行結果正確了！捐款總額等於600

![](/files/-MPaP3pibLumur7cutNL)

是我們所預期的總捐款金額。

> 那麼想想看，為什麼不用先前提過的 join() 來先限制p1執行緒結束後 再往下執行p2執行緒呢？

從本篇可以了解同步處理的重要與方便性。\
而且我們要注意若共用同個變數，必須特別去注意存取的順序。

### 完整範例程式碼(經同步處理)

```
class CDonate
{
   private static int sum=0;
   public synchronized static void add(int n)
   {
      int tmp=sum;
      tmp=tmp+n;
      try
      {
         Thread.sleep((int)(1000*Math.random()));
      }
      catch(InterruptedException e){}
      sum=tmp;
      System.out.println("捐款總額= "+sum);
  }
}
class CPerson extends Thread
{
   public void run()
   {
      for(int i=1;i<=3;i++)
         CDonate.add(100);
   }
}
public class synchronized_2
{
   public static void main(String args[])
   {
      CPerson p1=new CPerson();
      CPerson p2=new CPerson();
      p1.start();
      p2.start();
   }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://java.4-x.tw/java-15/java-15-6.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
