中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

synchronized關鍵字的使用

發布時間:2020-08-07 13:57:10 來源:網絡 閱讀:373 作者:nineteens 欄目:編程語言

  synchronized關鍵字是java并發編程中常使用的同步鎖,用于鎖住方法或者代碼塊,鎖代碼塊時可以是synchronized(this){}、synchronized(Object){}、synchronized(類class){}。

  當鎖住的內容執行完或者在執行過程中拋出異常,才會自動釋放鎖。如果想手動釋放鎖,需要調用鎖住的對象的wait()方法釋放掉鎖并且置于等待狀態,切換到其他線程運行,而notify()方法只是喚醒一個調用了該對象wait()方法的其他線程,但不會釋放鎖,選擇順序也不由代碼控制,由虛擬機實現。因此,對象的wait()、notify()、notifyAll()方法只能是配合synchronized關鍵字使用的,來完成線程間的調度。

  其中鎖住方法等同于synchronized(this){方法的所有代碼作為代碼塊},如下:

  public synchronized void test() {

  ...

  }

  等同于

  public void test() {

  synchronized (this) {

  ...

  }

  }

  上面的例子鎖住的是該類的對象,如果鎖住的是個靜態的方法,我們知道靜態方法是屬于類的而不屬于對象的,所以,synchronized修飾的靜態方法鎖定的是這個類的所有對象,即就算是兩個實例對象,只要他們都是這個類的,那都會鎖住。

  public synchronized static void test() {

  ...

  }

  等同于

  public static void test() {

  synchronized (所在類.class) {

  ...

  }

  }

  無論是鎖方法還是鎖代碼塊,無論鎖代碼塊時的參考對象是什么,只要記住一個原則就一目了然了,那就是當參考對象相同時,同步鎖才起作用,否則鎖不會互斥,可以并發執行。

  synchronized(this)表示當前類的對象實例相同時鎖起作用,synchronized(Object)表示該Object對象相同時鎖起作用,synchronized(類class)表示當都是該class類時鎖起作用。

  舉一個簡單的例子:

  public class TestController {

  public class Task implements Runnable{

  private String str;

  Task(String str){

  this.str=str;

  }

  @Override

  public void run() {

  synchronized (str) {

  try {

  Thread.sleep(3000l);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  System.out.println(str);

  }

  }

  }

  public static void main(String[] args) throws InterruptedException {

  TestController testController = new TestController();

  Thread thread1 = new Thread(testController.new Task("1"));

  Thread thread2 = new Thread(testController.new Task("1"));

  thread1.start();

  thread2.start();

  }

  }

  上述代碼,參照對象str都是"1",在java中,String字符串如果通過this.str="1"這樣的方式賦值就等同于str=String.valueOf("1"),如果字符串"1"之前已經初始化過,那就會直接拿之前的,所以是同一個對象。根據上面介紹的原則,那鎖就會起作用,所以結果是3秒之后輸出1,再過3秒再輸出1。

  如果把thread2改成

  Thread thread2 = new Thread(testController.new Task("2"));

  這時參考對象一個是"1",另一個是"2",不是同一個對象,所以鎖不會互斥,就不會起作用,所以結果是3秒后幾乎同時輸出1和2。

  以上都是多個線程同時調用同一個方法,如果調用不同的方法呢?

  public class Test{

  public synchronized void m1(){

  System.out.println("m1 running...");

  try {

  Thread.sleep(3000l);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  System.out.println("m1 end");

  }

  public synchronized void m2(){

  System.out.println("m2 running...");

  System.out.println("m2 end");

  }

  public static void main(String[] args) {

  Test test = new Test();

  new Thread(new Runnable() {

  @Override

  public void run() {

  test.m1();

  }

  }).start();

  new Thread(new Runnable() {

  @Override

  public void run() {

  test.m2();

  }

  }).start();

  }

  }

  上面代碼的輸出結果是:

  m1 running...

  //過3秒

  m1 end

  m2 running...

  m2 end

  上面就說過synchronized修飾在方法上等同于synchronized(this){方法的所有代碼作為代碼塊},而this就代表是對象,也就是說,第一個Thread獲得的是test對象的鎖,因為對象都是同一個test,所以第二個Thread無法獲取到鎖,而被阻塞。

  把上面的例子改造成如下:

  private String str = "1";

  public void m1(){

  synchronized(str){

  System.out.println("m1 running...");

  try {

  Thread.sleep(3000l);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  System.out.println("m1 end");

  }

  }

  public void m2(){

  synchronized(str){

  System.out.println("m2 running...");

  System.out.println("m2 end");

  }

  }無錫婦科醫院排名 http://www.csfk0731.com/

  第一個Thread調用m1()時獲取到的是對象str的鎖,第二個Thread調用m2()時也需要獲取對象str的鎖,而且因為是同一個Test對象,所以兩個str也是同一個對象,所以第二個Thread會因為獲取不到鎖而被阻塞,輸出結果和之前的例子一樣。

  如果再把上面的例子改造成如下:

  public class M1 {

  public void m(String str){

  synchronized (str) {

  System.out.println("m1 runing");

  try {

  Thread.sleep(3000l);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  System.out.println("m1 end");

  }

  }

  }

  public class M2 {

  public void m(String str){

  synchronized (str) {

  System.out.println("m2 runing");

  System.out.println("m2 end");

  }

  }

  }

  public class Test {

  public static void main(String[] args) {

  String str = "1";

  new Thread(new Runnable() {

  @Override

  public void run() {

  new M1().m(str);

  }

  }).start();

  new Thread(new Runnable() {

  @Override

  public void run() {

  new M2().m(str);

  }

  }).start();

  }

  }

  這次調用的方法在兩個類里面,但是結果和之前的兩個例子是一樣的,因為鎖住的都是傳進來的str對象,同一個對象只有一把鎖,第一個Thread拿了,第二個Thread就只能等待。

  總結:

  A. 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。

  B. 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。

  C. 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

华容县| 绩溪县| 永宁县| 邢台市| 新安县| 舞阳县| 湘潭县| 定南县| 桦甸市| 南宫市| 商城县| 通化市| 南部县| 商都县| 楚雄市| 桐庐县| 金阳县| 津南区| 南安市| 普安县| 金昌市| 黄冈市| 长宁县| 江口县| 汉寿县| 电白县| 霍山县| 塔河县| 出国| 天祝| 科技| 荃湾区| 大港区| 萨迦县| 扎囊县| 阳东县| 延庆县| 分宜县| 吉木乃县| 富顺县| 通许县|