java高並發synchronized學習


1.synchronized的作用:同步方法支持一種簡單的策略來防止線程干擾和內存一致性的錯誤:如果一個對象對多個線程可見,則對該對象的所有讀取或寫入都是通過同步方法來完成的。總的來說是能夠在同一時候保證最多只有一個線程執行該段代碼,以達到安全的效果。

2.synchronized是java的關鍵字,被java語言原生支持,是最基本的互斥同步手段

代碼演示

public class DisapperRequest1 implements  Runnable {
static int k=0;
static DisapperRequest1 disapperRequest1=new DisapperRequest1();
@Override
public void run() {
for(int i=0;i<100000;i++)
{
k++;
}
}

public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(disapperRequest1);
Thread thread1=new Thread(disapperRequest1);
thread.start();
thread1.start();
  /**join的意思是使得放棄當前線程的執行,並返回對應的線程,例如下面代碼的意思就是:
         程序在main線程中調用t1線程的join方法,則main線程放棄cpu控制權,並返回t1線程繼續執行直到線程t1執行完畢
         所以結果是t1線程執行完后,才到主線程執行,相當於在main線程中同步t1線程,t1執行完了,main線程才有執行的機會

thread.join();
thread1.join();
System.out.println(k);
}


}
join方法是通過調用線程的wait方法來達到同步的目的的。例如,A線程中調用了B線程的join方法,則相當於A線程調用了B線程的wait方法,在調用了B線程的wait方法后,A線程就會進入阻塞狀態
最后的結果總是小於或等於20W 這跟預期的結果不一樣。count++看上去只有一個操作,實際上是有三個操作的1.讀取count的值 2.講count加1 3.將count的值加入內存
當count的值還沒有加入內存的時候count就已經讀取了。這樣就會造成線程不安全。

3.Synchronized兩種方法用法:對象鎖:包括方法鎖(默認鎖對象為this當前的實例的對象)和同步代碼塊鎖(自己指定鎖對象)。類鎖:指的是用Synchronized修飾的靜態方法或者指定鎖對象為class對象
代碼塊形式要手動指定對象,方發鎖形式:Synchronized修飾普通方法,鎖對象默認為this

代碼塊鎖:isAlive方法判斷線程是否存活
public class SynchronizedObjectCodeBlock2 implements Runnable {
         static SynchronizedObjectCodeBlock2 instance=new SynchronizedObjectCodeBlock2();
    @Override
    public void run() {
        synchronized(this) {
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "運行結束");
        }
    }

    public static void main(String[] args) {
         Thread t1=new Thread(instance);
         Thread t2=new Thread(instance);
         t1.start();
         t2.start();
         while (t1.isAlive()||t2.isAlive())
         {

         }
         System.out.println("結束");
    }
}

 

當用兩個鎖的情況:當不是同一把鎖的時候,可以並行運行
public class SynchronizedObjectCodeBlock2 implements Runnable {
         static SynchronizedObjectCodeBlock2 instance=new SynchronizedObjectCodeBlock2();
         Object lock1=new Object();
         Object lock2=new Object();
    @Override
    public void run() {
        synchronized(lock1) {
            System.out.println(Thread.currentThread().getName()+"lock1");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "運行結束1");
        }
        synchronized(lock2) {
            System.out.println(Thread.currentThread().getName()+"lock2");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "運行結束2");
        }
    }

    public static void main(String[] args) {
         Thread t1=new Thread(instance);
         Thread t2=new Thread(instance);
         t1.start();
         t2.start();
         while (t1.isAlive()||t2.isAlive())
         {

         }
         System.out.println("結束");
    }
}
 
        

對象鎖:Synchronized修飾普通的方法,默認鎖對象為this

package com.xiaoqiang.sychronized;

public class SynchronizedObjectMethod3 implements Runnable {

    static SynchronizedObjectMethod3 instance=new SynchronizedObjectMethod3();

    @Override
    public void run() {
       method();

    }

    public static void main(String[] args) {
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive())
        {

        }
        System.out.println("結束");
    }

    public synchronized  void method()
    {
        System.out.println(Thread.currentThread().getName()+"lock1");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "運行結束1");
    }
}

類鎖:

1.staic 類鎖:假如不在method中加入staic修飾的話,兩個不同的靜態對象就會並行執行run方法

package com.xiaoqiang.sychronized;

public class SynchronizedClassStatic4 implements  Runnable {
    static  SynchronizedClassStatic4 instance1=new SynchronizedClassStatic4();
    static SynchronizedClassStatic4 instance2=new SynchronizedClassStatic4();
    @Override
    public void run() {
        method();
    }

    public static void main(String[] args) {
        Thread t1=new Thread(instance1);
        Thread t2=new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive())
        {

        }
        System.out.println("結束");
    }

    public synchronized  void method()
    {
        System.out.println(Thread.currentThread().getName()+"lock1");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "運行結束1");
    }
}

如果用 static 修飾method方法的話就會串行進行

package com.xiaoqiang.sychronized;

public class SynchronizedClassStatic4 implements  Runnable {
    static  SynchronizedClassStatic4 instance1=new SynchronizedClassStatic4();
    static SynchronizedClassStatic4 instance2=new SynchronizedClassStatic4();
    @Override
    public void run() {
        method();
    }

    public static void main(String[] args) {
        Thread t1=new Thread(instance1);
        Thread t2=new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive())
        {

        }
        System.out.println("結束");
    }

    public  static synchronized  void method()
    {
        System.out.println(Thread.currentThread().getName()+"lock1");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "運行結束1");
    }
}

 

2.。*.class 類鎖
同一個類鎖的實現
package com.xiaoqiang.sychronized;

public class SynchronizedClassClass5 implements Runnable {
    static  SynchronizedClassClass5 instance1=new SynchronizedClassClass5();
    static SynchronizedClassClass5 instance2=new SynchronizedClassClass5();
    @Override
    public void run() {
        method();
    }

    public static void main(String[] args) {
        Thread t1=new Thread(instance1);
        Thread t2=new Thread(instance2);
        t1.start();
        t2.start();
        while (t1.isAlive()||t2.isAlive())
        {

        }
        System.out.println("結束");
    }

   private  void method() {
       synchronized (SynchronizedClassClass5.class) {
           System.out.println(Thread.currentThread().getName() + "lock1");
           try {
               Thread.sleep(5000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(Thread.currentThread().getName() + "運行結束1");
       }
   }
}
 
        

4.Synchronized的核心思想:

1.一把鎖只能同時被一個線程獲取,沒有拿到鎖的線程必須等待。

2.每個實例都對應自己的一把鎖,不同實例之間互不影響。例外:鎖對象是*.class或者用Synchronized修飾的是static方法時,所有對象都共用同一把鎖

3.無論是正常運完畢或者方法拋出異常,都會釋放鎖。

 

5.Synchronized的性質

1.可重入性:指的是同一線程外層函數獲取到鎖后之后,內層函數可以直接再次獲取該鎖。

好處:避免死鎖,提高封裝性。

粒度(范圍):線程而非調用

2.不可中斷性:一旦這個鎖已經被別人獲得了,如果我還想獲得,就必須等待或者阻塞,直到別的線程釋放這個鎖。如果別人永遠不釋放鎖,那么只能永遠的等待下去。

6.Synchronized的缺點:

效率低:鎖的釋放情況少,試圖獲得鎖的時候不能設置超時,不能中斷一個正試圖獲得鎖的線程。

不夠靈活:加鎖和釋放鎖的時機單一,每個鎖僅有單一的條件,可能是不夠的。

無法知道是否成功獲取到鎖

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM