国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java走下神壇之同步代碼等同于斷面

2019-11-18 15:43:12
字體:
來源:轉載
供稿:網友

  同步經常作為斷面被引用。斷面是指一次只能有一個線程執行它。多個線程同時執行同步代碼是有可能的。

  這個誤解是因為很多程序員認為同步要害字鎖住了它所包圍的代碼。但是實際情況不是這樣的。同步加鎖的是對象,而不是代碼。因此,假如你的類中有一個同步方法,這個方法可以被兩個不同的線程同時執行,只要每個線程自己創建一個的該類的實例即可。



  參考下面的代碼:

class Foo extends Thread
{
 PRivate int val;
 public Foo(int v)
 {
  val = v;
 }
 public synchronized void printVal(int v)
 {
  while(true)
   System.out.println(v);
 }
 public void run()
 {
  printVal(val);
 }
}
class SyncTest
{
 public static void main(String args[])
 {
  Foo f1 = new Foo(1);
  f1.start();
  Foo f2 = new Foo(3);
  f2.start();
 }
}
  運行SyncTest產生的輸出是1和3交叉的。假如printVal是斷面,你看到的輸出只能是1或者只能是3而不能是兩者同時出現。程序運行的結果證實兩個線程都在并發的執行printVal方法,即使該方法是同步的并且由于是一個無限循環而沒有終止。

  要實現真正的斷面,你必須同步一個全局對象或者對類進行同步。下面的代碼給出了一個這樣的范例。

class Foo extends Thread
{
 private int val;
 public Foo(int v)
 {
  val = v;
 }
 public void printVal(int v)
 {
  synchronized(Foo.class) {
   while(true)
    System.out.println(v);
  }
 }
 public void run()
 {
  printVal(val);
 }
}
  上面的類不再對個別的類實例同步而是對類進行同步。對于類Foo而言,它只有唯一的類定義,兩個線程在相同的鎖上同步,因此只有一個線程可以執行printVal方法。

  這個代碼也可以通過對公共對象加鎖。例如給Foo添加一個靜態成員。兩個方法都可以同步這個對象而達到線程安全。

  譯者注:

  下面筆者給出一個參考實現,給出同步公共對象的兩種通常方法:

  1、

class Foo extends Thread
{
 private int val;
 private static Object lock=new Object();
 public Foo(int v)
 {
  val = v;
 }
 public void printVal(int v)
 {
  synchronized(lock) {
   while(true)
    System.out.println(v);
  }
 }
 public void run()
 {
  printVal(val);
 }
}
  上面的這個例子比原文給出的例子要好一些,因為原文中的加鎖是針對類定義的,一個類只能有一個類定義,而同步的一般原理是應該盡量減小同步的粒度以到達更好的性能。筆者給出的范例的同步粒度比原文的要小。

  2、

class Foo extends Thread
{
 private String name;
 private String val;
 public Foo(String name,String v)
 {
  this.name=name;
  val = v;
 }
 public void printVal()
 {
  synchronized(val) {
   while(true) System.out.println(name+val);
  }
 }
 public void run()
 {
  printVal();
 }
}
public class SyncMethodTest
{
 public static void main(String args[])
 {
  Foo f1 = new Foo("Foo 1:","printVal");
  f1.start();
  Foo f2 = new Foo("Foo 2:","printVal");
  f2.start();
 }
}
  上面這個代碼需要進行一些額外的說明,因為JVM有一種優化機制,因為String類型的對象是不可變的,因此當你使用""的形式引用字符串時,假如JVM發現內存已經有一個這樣的對象,那么它就使用那個對象而不再生成一個新的String對象,這樣是為了減小內存的使用。

  上面的main方法其實等同于:



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 无极县| 隆化县| 江北区| 四子王旗| 呈贡县| 龙胜| 普洱| 灵宝市| 奉化市| 阿合奇县| 渝中区| 昌邑市| 滦南县| 湘西| 黑龙江省| 独山县| 东方市| 永春县| 平阴县| 芦溪县| 宁蒗| 刚察县| 高唐县| 鞍山市| 荔波县| 和平县| 石城县| 西城区| 隆安县| 伊金霍洛旗| 博乐市| 霍邱县| 龙陵县| 宁晋县| 满洲里市| 淮南市| 西平县| 永城市| 平邑县| 怀来县| 焦作市|