天天看點

JAVA中利用 同步代碼塊 或 同步函數 解決線程的安全問題

線程的安全問題

當一個線程在執行操作共享資料的多條代碼的過程中,其它線程參與運算,就會導緻線程問題的産生

解決思路:

将多條操作共享資料的線程代碼封裝起來,當線程在執行這些代碼的時候,
      其他線程不可以參與運算.
      必須要目前把這些代碼執行完畢後,其它線程才可以參與運算.
           

同步代碼

同步代碼塊的格式:
        synchronized(對象)
        {
            需要被同步的代碼;
        }
           

例子:

class Ticket implements Runnable  //Ticket票
{
    private int num = 100;
    Object obj = new Object();
    public void run()
    {
        while(true)
        {
        //同步代碼塊
            synchronized(obj)
            {
                if (num > 0)
                {
                    
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e)
                    {}

                     
                    System.out.println(Thread.currentThread().getName() + "......總票數剩餘" + num--);
                }
            }
        }
    }
}
public class Demo{
    public static void main(String[] args){

        Ticket t = new Ticket(); //建立一個線程任務對象

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
           

運作多次的結果:

(1)

JAVA中利用 同步代碼塊 或 同步函數 解決線程的安全問題

(2)

JAVA中利用 同步代碼塊 或 同步函數 解決線程的安全問題

同步的好處:解決了線程的安全問題

同步的弊端: 相對降低了效率....因為同步外的線程都會判斷同步鎖
		(因為如果有線程在同步裡面,剛好CPU又突然給别的線程權限,但又進不去)
		(等到CPU重新給到在同步代碼塊裡面的執行完畢出來後,才能給别的線程進去,是以降低了效率.)
	
   同步的前提: 同步中必須有多線程并使用同一個鎖
           

.

.

.

.

同步函數

就是把同步代碼塊封裝起來

例子:

public synchronized void show(){	//把同步代碼塊封裝起來
        if (num > 0) {
            try {
                Thread.sleep(10);
            }
            catch (InterruptedException e) {

            }
            System.out.println(Thread.currentThread().getName() + "...function...總票數剩餘" + num--);
        }
           
這裡面的鎖是對象是 this 也就是 它本身
           

也就說在上面的例子中我們可以不用Object 建立一個對象來當鎖,而可以用自己的鎖 this

可以寫成這樣

synchronized (this) {
    if (num > 0) {
      try {
		Thread.sleep(10);
      } catch (InterruptedException e) {
      }
    }
  System.out.println(Thread.currentThread().getName() + "....總票數剩餘" + num--);
 }
           

同步函數使用的鎖是this

同步函數和同步代碼塊的差別:

同步函數的鎖是固定的this.

   同步代碼塊的鎖是任意的對象
           

建議使用同步代碼塊

因為同步函數雖然簡化,但是鎖是唯一的…this

.

.

.

.

.

靜态的同步函數

靜态的同步函數使用的鎖:

該函數所屬位元組碼對象 可以用 getClass()方法擷取

也可以用目前 類名.class 表示
           

例子:

可以

this.getClass()

//this目前的

Ticket是上面的類名 也可以

Ticket.class

synchronized(Ticket.class)
            {
                if (num > 0)
                {
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e)
                    {}

                     
                    System.out.println(Thread.currentThread().getName() + "......總票數剩餘" + num--);
                }
           

一般隻要保證多個線程用同一個鎖就行!!!