2025-02-09

1.在使用多線程時要註意run方法和start方法的區別
    t.run();main線程調用t的run方法,並沒有創建新線程。

    t.start();創建一個新的線程t,並執行。

view plaincopy to clipboardprint?public class PuzzleDemo76{ 
    public static synchronized void main(String args[]){    //主線程獲得PuzzleDemo76對象的鎖  
        Thread t = new Thread(){ 
            public void run(){ 
                pong(); 
            } 
        }; 
        t.start(); 
        System.out.println("ping"); 
    } 
    static synchronized void pong(){    //等待main線程執行完畢,才能夠使得t線程獲得鎖  
        System.out.println("pong"); 
    } 

public class PuzzleDemo76{
 public static synchronized void main(String args[]){ //主線程獲得PuzzleDemo76對象的鎖
  Thread t = new Thread(){
   public void run(){
    pong();
   }
  };
  t.start();
  System.out.println("ping");
 }
 static synchronized void pong(){ //等待main線程執行完畢,才能夠使得t線程獲得鎖
  System.out.println("pong");
 }
}

 

2.Thread的join()方法註意點
表示正在被鏈接的Thread實例調用wait方法,因此會釋放鎖。

因此如果你需要某個對象的鎖的完全控制,則必須確保沒有其他線程訪問。

view plaincopy to clipboardprint?import java.util.*; 
public class PuzzleDemo77{ 
    public static void main(String args[])throws Exception{ 
        final Worker w = new Worker(); 
        Thread t = new Thread(w); 
        t.start(); 
        Timer timer = new Timer(true); 
        timer.schedule(new TimerTask(){ 
            public void run(){ 
                w.keepWorking(); 
            } 
        },500); 
        Thread.sleep(400); 
        w.quit();   //獲得w的鎖,並執行方法  
    } 

class Worker implements Runnable{ 
    private volatile boolean quitTime = false; 
    public void run(){ 
        while(!quitTime){ 
            pretendToWork(); 
        } 
        System.out.println("Beer is good"); 
    } 
    private void pretendToWork(){ 
        try{ 
            Thread.sleep(300); 
        } 
        catch(Exception e){ 
             
        } 
    } 
    synchronized void quit() throws Exception{ 
        quitTime = true; 
        Thread.yield();//釋放鎖  
    } 
    synchronized void keepWorking(){ 
        quitTime = true; 
    } 

import java.util.*;
public class PuzzleDemo77{
 public static void main(String args[])throws Exception{
  final Worker w = new Worker();
  Thread t = new Thread(w);
  t.start();
  Timer timer = new Timer(true);
  timer.schedule(new TimerTask(){
   public void run(){
    w.keepWorking();
   }
  },500);
  Thread.sleep(400);
  w.quit(); //獲得w的鎖,並執行方法
 }
}
class Worker implements Runnable{
 private volatile boolean quitTime = false;
 public void run(){
  while(!quitTime){
   pretendToWork();
  }
  System.out.println("Beer is good");
 }
 private void pretendToWork(){
  try{
   Thread.sleep(300);
  }
  catch(Exception e){
   
  }
 }
 synchronized void quit() throws Exception{
  quitTime = true;
  Thread.yield();//釋放鎖
 }
 synchronized void keepWorking(){
  quitTime = true;
 }
}

 

3.HashSet的問題
HashSet<String>s = new HashSet<String>();

Iterator i = s.iterator();    這裡的i是HashMap.keyIterator類型的。但是因為這個類型是不同包中且非公共的,因此不能調用他的方法。

class HashSet{

    private transient HashMap<E,Object> map;

    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

}
 

view plaincopy to clipboardprint?import java.util.*; 
import java.lang.reflect.*; 
public class PuzzleDemo78{ 
    public static void main(String args[])throws Exception{ 
        Set<String> s = new HashSet<String>(); 
        s.add("foo"); 
        Iterator iter = s.iterator(); 
        Method m = Iterator.class.getMethod("hasNext"); 
        System.out.println(m.invoke(iter)); 
    } 

import java.util.*;
import java.lang.reflect.*;
public class PuzzleDemo78{
 public static void main(String args[])throws Exception{
  Set<String> s = new HashSet<String>();
  s.add("foo");
  Iterator iter = s.iterator();
  Method m = Iterator.class.getMethod("hasNext");
  System.out.println(m.invoke(iter));
 }
}


4.編譯器尋找調用方法的規則:在正確的名稱方法的最內層作用域查找需要調用的方法。


5.Class.newInstance和內部類
Class.newInstance()是調用一個空的構造器。

而非靜態內部類調用空構造器時,會有一個隱藏的一個參數即外部類實例,因此外表看起來是空的內部類構造器並不是空構造器。

結論:避免使用反射實例化內部類。

view plaincopy to clipboardprint?import java.lang.reflect.*; 
public class PuzzleDemo80{ 
    public static void main(String args[])throws Exception{ 
        new PuzzleDemo80().greetWorld(); 
    } 
    private void greetWorld()throws Exception{ 
        Constructor c = Inner.class.getConstructor(PuzzleDemo80.class); 
        System.out.println(c.newInstance(PuzzleDemo80.this)); 
    } 
    public class Inner{ 
        public Inner(){} 
        public String toString(){ 
            return "Hellow"; 
        } 
    } 

import java.lang.reflect.*;
public class PuzzleDemo80{
 public static void main(String args[])throws Exception{
  new PuzzleDemo80().greetWorld();
 }
 private void greetWorld()throws Exception{
  Constructor c = Inner.class.getConstructor(PuzzleDemo80.class);
  System.out.println(c.newInstance(PuzzleDemo80.this));
 }
 public class Inner{
  public Inner(){}
  public String toString(){
   return "Hellow";
  }
 }
}

 

6.System.out的一個瑕疵
System.out是一個PrintStream,因此帶有緩沖區,但是可以自動刷新。

但是有一個方法例外!

write(int)是唯一一個在自動刷新功能開啟的情況下不刷新PrintStream輸出流的方法。

view plaincopy to clipboardprint?public class PuzzleDemo81{ 
    public static void main(String args[]){ 
        String greeting = "Hello "; 
        for(int i=0;i<greeting.length();i++){ 
            System.out.println(greeting.charAt(i)); 
        } 
    } 

public class PuzzleDemo81{
 public static void main(String args[]){
  String greeting = "Hello ";
  for(int i=0;i<greeting.length();i++){
   System.out.println(greeting.charAt(i));
  }
 }
}

 

7.復制對象的簡單方法及解決
實現瞭io.serializable的類可以簡單的通過writeObject和readObject復制對象,並生成一個新的對象。

如果一個類是Singleton,因此隻能有一個對象,怎麼能夠解決這個問題使得通過writeObject和readObject後的對象還是其本身呢?

private Object readResolve(){

    return **;

}

 view plaincopy to clipboardprint?import java.io.*; 
class Dog extends Exception{ 
    public static final Dog INSTANCE = new Dog(); 
    private Dog(){} 
    public String toString(){ 
        return "woof"; 
    } 
    private Object readResolve(){   //實現readResolve方法,使得隻有一個實例  
        return INSTANCE; 
    } 

public class PuzzleDemo83{ 
    public static void main(String args[])throws Exception{ 
        Dog dog = Dog.INSTANCE; 
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt")); 
        out.writeObject(dog); 
        out.close(); 
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("1.txt")); 
        Dog dog2 = (Dog)in.readObject(); 
        in.close(); 
        System.out.println(dog==dog2); 
    } 

import java.io.*;
class Dog extends Exception{
 public static final Dog INSTANCE = new Dog();
 private Dog(){}
 public String toString(){
  return "woof";
 }
 private Object readResolve(){ //實現readResolve方法,使得隻有一個實例
  return INSTANCE;
 }
}
public class PuzzleDemo83{
 public static void main(String args[])throws Exception{
  Dog dog = Dog.INSTANCE;
  ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
  out.writeObject(dog);
  out.close();
  ObjectInputStream in = new ObjectInputStream(new FileInputStream("1.txt"));
  Dog dog2 = (Dog)in.readObject();
  in.close();
  System.out.println(dog==dog2);
 }
}


8.Thread.interrupted()和Thread.isInterrupted()的 區別
Thread.interrupted()方法後會清除當前線程的中斷狀態。

Thread.isInterrupted()則隻是測試是否已經被中斷。

 view plaincopy to clipboardprint?public class PuzzleDemo84{ 
    public static void main(String args[]){ 
        Thread.currentThread().interrupt(); 
        if(Thread.currentThread().isInterrupted 
 
()){ 
            System.out.println 
 
("Interrupt:"+Thread.currentThread().isInterrupted()); 
        } 
        else{ 
            System.out.println(" Not  
 
Interrupt:"+Thread.currentThread().isInterrupted()); 
        } 
    } 

public class PuzzleDemo84{
 public static void main(String args[]){
  Thread.currentThread().interrupt();
  if(Thread.currentThread().isInterrupted

()){
   System.out.println

("Interrupt:"+Thread.currentThread().isInterrupted());
  }
  else{
   System.out.println(" Not

Interrupt:"+Thread.currentThread().isInterrupted());
  }
 }
}


9.多線程下的初始化
當一個線程訪問一個類的某個成員之前,都會去檢查這個類是否已經被初始化。

多線程下類初始化有4種情況:

(1)這個類沒被初始化。

(2)這個類被當前線程初始化。

(3)這個類被其他線程初始化。

(4)這個類已經被初始化。

當第三種情況下,如果B線程要訪問A類的某個成員,則發現正在被C線程初始化,則會等待C線程初始化完畢,才會繼續運行。

結論:要明確初始化順序。

view plaincopy to clipboardprint?public class PuzzleDemo85{ 
    private static boolean initialize = true;       //1  
    private static Thread t = new Thread(new Runnable(){    //2  
            public void run(){ 
                initialize = true; 
            } 
        }); 
    static{ 
        System.out.println(initialize); 
        t.start();      //3  
         
    } 
    public static void main(String args[]){ 
        try{ 
            System.out.println("main:"+initialize); 
            t.join();   //4  
        } 
        catch(Exception e){} 
        System.out.println(initialize); //5  
    } 

public class PuzzleDemo85{
 private static boolean initialize = true;  //1
 private static Thread t = new Thread(new Runnable(){ //2
   public void run(){
    initialize = true;
   }
  });
 static{
  System.out.println(initialize);
  t.start();  //3
  
 }
 public static void main(String args[]){
  try{
   System.out.println("main:"+initialize);
   t.join(); //4
  }
  catch(Exception e){}
  System.out.println(initialize); //5
 }
}

 作者“xiazdong的專欄”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *