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的專欄”