1. 程式人生 > >十四、十五天筆記總結

十四、十五天筆記總結

io流、多線程

1.
LineNumberReader:
 *public int getLineNumber():獲取行號
 *public void setLineNumber(int lineNumber):設置起始行號
  String readLine():讀取一行
   案例:讀取文件,每次讀取一行打印並且加上行號
   packagecom.edu_01;
 
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
 
/**
 * 1.
  LineNumberReader:
 *public int getLineNumber():獲取行號
 *public void setLineNumber(int lineNumber):設置起始行號
  String readLine():讀取一行
       案例:讀取文件,每次讀取一行打印並且加上行號
 *
 */
public class LineNumberReaderDemo {
         publicstatic void main(String[] args) throws IOException {
                   //創建LineNumberReader對象
                   //publicLineNumberReader(Reader in)
                   LineNumberReaderlnr = new LineNumberReader(new FileReader("a.txt"));
                  
                   //默認起始行號從0開始
                   //設置其實行號為從10開始
                   lnr.setLineNumber(10);
                  
                   //一次讀取一行
                   Stringline;
                   while((line = lnr.readLine())!=null) {
                            //打印每一行的行號和內容
                            System.out.println(lnr.getLineNumber()+":"+line);
                   }
                  
                   //關流
                   lnr.close();
         }
 
}
2.操作基本數據類型的流
 
 * 可以操作基本類型的流對象。
 *DataInputStream:讀數據
 *DataOutputStream:寫數據
 *
 案例:給流中寫基本類型的數據,並且讀取
 註意:
 * 讀寫順序必須一致,否則數據有問題。
package com.edu_02;
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
/**
 * 2.操作基本數據類型的流
 * 可以操作基本類型的流對象。
 *DataInputStream:讀數據
 *DataOutputStream:寫數據
 案例:給流中寫基本類型的數據,並且讀取
 註意:
 * 讀寫順序必須一致,否則數據有問題。
 *
 */
public class DataOutputStreamDemo {
         publicstatic void main(String[] args) throws IOException {
                   //寫數據
                   //write();
                   read();
         }
 
         privatestatic void read() throws IOException {
                   //DataInputStream:讀數據
                   //創建對象:publicDataInputStream(InputStream in)
                   DataInputStreamdis = new DataInputStream(new FileInputStream("dos.txt"));
                  
                   //讀數據了,按什麽順序寫入就必須按照什麽順序讀出來
                   System.out.println(dis.readByte());
                   System.out.println(dis.readShort());
                   System.out.println(dis.readInt());
                   System.out.println(dis.readLong());
                   System.out.println(dis.readChar());
                   System.out.println(dis.readFloat());
                   System.out.println(dis.readDouble());
                   System.out.println(dis.readBoolean());
                  
                   //關流
                   dis.close();
         }
 
         privatestatic void write() throws IOException {
                   //publicDataOutputStream(OutputStream out)
                   DataOutputStreamdos = new DataOutputStream(new FileOutputStream("dos.txt"));
                  
                   //給流關聯的文件中寫入基本類型的數據
                   dos.writeByte(20);
                   dos.writeShort(200);
                   dos.writeInt(2000);
                   dos.writeLong(20000L);
                  
                   dos.writeChar(97);
                   dos.writeFloat(12.34F);
                   dos.writeDouble(23.34);
                   dos.writeBoolean(true);
                  
                   //關流
                   dos.close();
         }
 
}
 
3.
 內存操作流:解決臨時數據存儲的問題。
 操作字節數組(演示著一個案例即可)
 ByteArrayInputStream
 ByteArrayOutputStream
 byte[] toByteArray() 將之前寫入內存的流轉換成字節數組
 
 
 操作字符數組
 CharArrayReader
 CharArrayWrite
 
 
 操作字符串
 StringReader
 StringWriter
 
 
 案例:演示
 操作字節數組
 ByteArrayInputStream
 ByteArrayOutputStream
 
 將數據寫到流中保存在內存,並且讀取
 packagecom.edu_03;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
 
/**
 *  操作字節數組(演示著一個案例即可)
          ByteArrayInputStream
          ByteArrayOutputStream
          byte[] toByteArray() 將之前寫入內存的流轉換成字節數組
 *
 */
public class ByteArrayOutputStreamDemo {
         publicstatic void main(String[] args) throws IOException {
                   //給內存中寫數據publicByteArrayOutputStream()
                   ByteArrayOutputStreambaos = new ByteArrayOutputStream();
                   //給內存中調用方法寫數據
                   baos.write("hello".getBytes());
                   //將寫入內存中的數據讀取出來
                   byte[]buf = baos.toByteArray();//調用這個方法,將之前寫入內存中的數據存儲到字節數組中
                   ByteArrayInputStreambais = new ByteArrayInputStream(buf);//將剛才存儲到字節數組中的內容關聯上bais
                  
                   //只有這樣之後,我們才可以直接從bais中讀取我們想要的內容
                   //一次讀取一個字節
                   intby;
                   while((by=bais.read())!=-1) {
                            System.out.print((char)by);
                   }
                   //關流
                   bais.close();
                   baos.close();
         }
 
}
 
 4.
 * 打印流:
 *             字節打印流              PrintStream
 *             字符打印流              PrintWriter
 *
 * 特點:
 *             A:只能操作目的地,不能操作數據源
 *             B:可以操作任意類型的數據
 *             C:如果啟動了自動刷新,能夠自動刷新
 *             D:可以操作文件的流
 *                      註意:什麽流可以直接操作文件?
                            看流對象的API,如果其構造方法同時有File和String類型的參數,就可以直接操作文件。
 
 
案例1:利用字符打印流給文件中書寫數據(String類型),需要手動刷新
package com.edu_04;
 
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 *  4.
 * 打印流:
 *             字節打印流              PrintStream
 *             字符打印流              PrintWriter
 *
 * 特點:
 *             A:只能操作目的地,不能操作數據源
 *             B:可以操作任意類型的數據
 *             C:如果啟動了自動刷新,能夠自動刷新
 *             D:可以操作文件的流
 *                      註意:什麽流可以直接操作文件?
                            看流對象的API,如果其構造方法同時有File和String類型的參數,就可以直接操作文件。
 *
 */
public class PrintWriterDemo {
         publicstatic void main(String[] args) throws IOException {
                   //使用打印流給文件中寫入hello,java,world
                   //publicPrintWriter(String fileName)
                   PrintWriterpw = new PrintWriter("pw.txt");
                  
                   //給流關聯的文件中寫數據
                   pw.write("hello");
                   pw.write("java");
                   pw.write("world");
                  
                   //刷新
                   pw.flush();
                  
                   //3.關流
                   pw.close();
                  
         }
 
}
 * 操作任意類型的數據呢?
 *print()
 *println():如果啟動了自動刷新,能夠實現刷新,而且還實現了自動換行。
 * 如何啟動自動刷新:利用構造
 *PrintWriter(OutputStream out, boolean autoFlush)
 *PrintWriter(Writer out, boolean autoFlush)
 *
 * 如果啟用了自動刷新,則只有在調用 println、printf 或 format 的其中一個方法時才可能完成此操作
 
案例3:利用字符打印流復制java文件(BufferedReader+PrintWriter)
 
package com.edu_04;
 
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
 
public class PrintWriterDemo3 {
         publicstatic void main(String[] args) throws IOException {
                   /**
                    * 案例3:利用字符打印流復制java文件(BufferedReader+PrintWriter)
                    */
                   //數據源
                   BufferedReaderbr = new BufferedReader(new FileReader("PrintWriterDemo.java"));
                   //目的地
                   //PrintWriter(Writerout, boolean autoFlush)
                   PrintWriterpw = new PrintWriter(new FileWriter("copy.java"),true);
                  
                   //讀一行寫一行
                   Stringline;
                   while((line=br.readLine())!=null) {
                            pw.println(line);//1.寫數據  2.換行  3.刷新
                  }
                  
                   //關流
                   pw.close();
                   br.close();
                  
         }
 
}
 
5.標準輸入輸出流
 *System類下有這樣的兩個成員變量:
 
 * 標準輸入流:
 *             public static final InputStream in
 
 案例1:利用標註輸入流進行鍵盤錄入,錄入後讀取流並打印在控制臺
 packagecom.edu_05;
 
import java.io.IOException;
import java.io.InputStream;
 
public class SystemIn {
         publicstatic void main(String[] args) throws IOException {
                   /**
                    * public static final InputStream in
                    */
                   //將鍵盤錄入的數據封裝在了輸入流中
                   //Scannersc = new Scanner(System.in);
                   InputStreamis = System.in;
                  
                   //將鍵盤錄入的數據從輸入流中讀取出來
                   intby;
                   while((by=is.read())!=-1) {
                            System.out.print((char)by);
                   }
                  
                   //關流
                   is.close();
         }
 
}
 案例2:用IO流實現鍵盤錄入,一次讀取一行數據
                    分析:
                  InputStream is = System.in;
                    BufferedReader是字符緩沖流,是對字符流進行高效操作的
                    所以,參數必須是字符類型
                    而我們現在有的是字節類型的流
                    請問:怎麽辦呢?轉換流
 packagecom.edu_05;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class SystemIn2 {
         publicstatic void main(String[] args) throws IOException {
                   /**
                    * 案例2:用IO流實現鍵盤錄入,一次讀取一行數據
                    * InputStream is = System.in;
                    * InputSreamReader isr = newInputStreamReader(is)
                    * BufferedReader br = new BufferedReader(isr);
                    */
                   //將上面的分析寫為一部
                   BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));
                  
                   //一次讀取一行數據
                   System.out.println("請輸入你的姓名");
                   Stringname = br.readLine();
                   System.out.println("請輸入你的年齡");
                   Stringage = br.readLine();
                  
                   System.out.println(name+":"+age);
         }
 
}
 * 標準輸出流:
 *             public static final PrintStream out
 
 案例:解析輸出語句System.out.println("helloworld");
   packagecom.edu_05;
 
import java.io.PrintStream;
 
/**
 *  標準輸出流:
 *   public static final PrintStream out
        案例:解析輸出語句System.out.println("helloworld");
 *
 */
public class SystemOut {
         publicstatic void main(String[] args) {
//               PrintStreamps = System.out;
//               ps.println(true);
                  
                   //上面兩行合並為一行,底層調用的字節打印流中的方法
                   System.out.println(true);
         }
}
  
 
6.
 * 合並流:SequenceInputStream類可以將多個輸入流串流在一起,合並為一個輸入流,因此,該流也被稱為合並流。
   
   構造:
  SequenceInputStream(InputStream s1, InputStream s2) :將s1和s2合並成一個輸入流,先讀取s1後讀取s2
 
 *
 * 案例1:
 *             我要把DataStreamDemo.java和ByteArrayStreamDemo.java寫到一個文件Copy.java
 *
 * 數據源:
 *             DataStreamDemo.java
 *             ByteArrayStreamDemo.java
 * 目的地:
 *             Copy.java
   packagecom.edu_06;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
 
/**
 * 6.
 * 合並流:SequenceInputStream類可以將多個輸入流串流在一起,合並為一個輸入流,因此,該流也被稱為合並流。
   
   構造:
  SequenceInputStream(InputStream s1, InputStream s2) :將s1和s2合並成一個輸入流,先讀取s1後讀取s2
 
 *
 * 案例1:
 *             我要把DataStreamDemo.java和ByteArrayStreamDemo.java寫到一個文件Copy.java
 *
 * 數據源:
 *             DataStreamDemo.java
 *             ByteArrayStreamDemo.java
 * 目的地:
 *             Copy.java
 *
 */
public class SequenceInputStreamDemo {
         publicstatic void main(String[] args) throws IOException {
                   //創建合並流對象
                   //SequenceInputStream(InputStreams1, InputStream s2) :將s1和s2合並成一個輸入流,先讀取s1後讀取s2
                   //將兩個數據源合而為一
                   SequenceInputStreamsis = new SequenceInputStream(newFileInputStream("PrintWriterDemo.java"), newFileInputStream("SystemIn2.java"));
                   //封裝目的地
                   FileOutputStreamfos = new FileOutputStream("copy2.java");
                  
                   //一下讀寫一個字節數組
                   byte[]buf = new byte[1024];
                   intlen;
                   while((len=sis.read(buf))!=-1) {
                            //讀多少寫多少
                            fos.write(buf,0, len);
                   }
                  
                   //關流
                   fos.close();
                   sis.close();
                  
         }
 
}
 
 
 
8. 對象的序列化和反序列化
 * 序列化流:把對象按照流一樣的方式寫到文件或者在網絡中傳輸。      
 * 反序列化流:把文件或者網絡中的流對象數據還原對象。
 *
 *ObjectOutputStream:序列化流
  writeObject(Object obj) 將指定的對象寫入 ObjectOutputStream。
  
 *ObjectInputStream:反序列化流
  Object readObject() 從 ObjectInputStream 讀取對象。
 *
   註意:如果一個類不是實現Serializable接口無法把實例化,會報異常java.io.NotSerializableException
 * 類通過實現java.io.Serializable 接口以啟用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。
 *
 * 如何實現序列化?
 *             讓對象所屬類的實現序列化接口。  
  
  
  
 
9. Properties(查看api實現map接口本質是一個map集合)
 9.1
 *Properties:Properties 類表示了一個持久的屬性集。屬性列表中每個鍵及其對應值都是一個字符串。                
 * 特點:Properties可保存在流中或從流中加載。
   案例:使用map集合的put方法給集合中存儲數據並且遍歷
  
 
 9.2
 *Properties的特有功能:
 *             A:添加元素
 *                      public ObjectsetProperty(String key,String value)
 *             B:獲取元素
 *                      public StringgetProperty(String key)
 *                      public Set<String>stringPropertyNames()
 案例:使用它的特有功能添加元素並遍歷
 
 packagecom.edu_08;
 
import java.util.Properties;
import java.util.Set;
 
/**
 *  9.2
 *Properties的特有功能:
 *             A:添加元素
 *                      public ObjectsetProperty(String key,String value)
 *             B:獲取元素
 *                      public StringgetProperty(String key)
 *                      public Set<String>stringPropertyNames()
        案例:使用它的特有功能添加元素並遍歷
 *
 */
public class PropertiesDemo2 {
         publicstatic void main(String[] args) {
                   //創建Properties這個集合
                   Propertiesprop = new Properties();
                  
                   //調用publicObject setProperty(String key,String value)
                   prop.setProperty("huangxiaoming","baby");
                   prop.setProperty("dengchao","sunli");
                   prop.setProperty("xidada","pengliyuan");
                  
                   //1.獲取所有鍵的集合
                   //publicSet<String> stringPropertyNames()
                   Set<String>keys = prop.stringPropertyNames();
                   //遍歷鍵,根據鍵找值
                   for(String key : keys) {
                            System.out.println(key+":"+prop.getProperty(key));
                   }
                  
                  
         }
 
}
 9.3
 * 可以和IO流進行結合使用:
 *             把文件中的數據加載到集合中。註意:文件中的數據必須是鍵值對象形式的(例如:張傑=謝娜)。
 *             public void load(InputStreaminStream)
 *             public void load(Reader reader)
                   案例:創建一個鍵值對文件,將文件中的鍵值對加載到集合中,輸出集合
                   packagecom.edu_08;
 
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
 
/**
 * 可以和IO流進行結合使用:
 *             把文件中的數據加載到集合中。註意:文件中的數據必須是鍵值對象形式的(例如:張傑=謝娜)。
 *             public void load(InputStreaminStream)
 *             public void load(Reader reader)
                   案例:創建一個鍵值對文件,將文件中的鍵值對加載到集合中,輸出集合
 *
 */
public class PropertiesDemo3 {
         publicstatic void main(String[] args) throws IOException {
                   //創建集合
                   Propertiesprop = new Properties();
                  
                   //將文件中的鍵值對,加載到集合中
                   prop.load(newFileReader("prop.txt"));
                  
                   //遍歷集合
                   Set<String>keys = prop.stringPropertyNames();
                   for(String key : keys) {
                            System.out.println(key+":"+prop.getProperty(key));
                   }
                  
         }
 
}
 *
 *             把集合中的數據存儲到文本文件中,並且是按照鍵值對形式存儲的。
 *             public void store(OutputStreamout,String comments)
 *              public void store(Writerwriter,String comments)
                   案例:將創建的鍵值對集合加載到文件中
   packagecom.edu_08;
 
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
 
/**
 *  把集合中的數據存儲到文本文件中,並且是按照鍵值對形式存儲的。
 *             public void store(OutputStreamout,String comments)
 *              public void store(Writerwriter,String comments)
                   案例:將創建的鍵值對集合加載到文件中
 *
 */
public class PropertiesDemo4 {
         publicstatic void main(String[] args) throws IOException {
                   //創建集合
                   Propertiesprop = new Properties();
                  
                   //給集合中存儲數據
                   prop.setProperty("liudehua","50");
                   prop.setProperty("liming","60");
                   prop.setProperty("zhangxueyou","40");
                  
                   //將集合中的元素,存儲到文本文件中
                   prop.store(newFileWriter("prop2.txt"), "name=age");
                  
         }
 
}
  
案例:我有一個文本文件,我知道數據是鍵值對形式的,但是不知道內容是什麽。
           請寫一個程序判斷是否有“lisi”這樣的鍵存在,如果有就改變其值為”100”
   packagecom.edu_09;
 
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
 
public class PropTest {
         publicstatic void main(String[] args) throws IOException {
                   /**
                    * 案例:我有一個文本文件,我知道數據是鍵值對形式的,但是不知道內容是什麽。
                                 請寫一個程序判斷是否有“lisi”這樣的鍵存在,如果有就改變其值為”100”
                                
          zhangsan=3
          lisi=4
          wangwu=5
          1.創建集合對象
          2.將文件中的鍵值對加載到集合中
          3.獲取多有的鍵的集合,遍歷,判斷
          4.如果存在lisi,的話,給集合中重新存儲鍵值對lisi=100
          5.將集合中的數據存儲到文件中
                    */
                   //1.創建集合對象
                   Propertiesprop = new Properties();
                  
                   //2.將文件中的鍵值對加載到集合中
                   prop.load(newFileReader("prop3.txt"));
                  
                   //3.獲取多有的鍵的集合,遍歷,判斷
                   Set<String>keys = prop.stringPropertyNames();
                  
                   //4.如果存在lisi,的話,給集合中重新存儲鍵值對lisi=100
                   for(String key : keys) {
                            if("lisi".equals(key)) {
                                     prop.setProperty(key,"100");
                            }
                   }
                  
                   //5.將集合中的數據存儲到文件中
                   prop.store(newFileWriter("prop3.txt"), null);
                  
         }
 
}
案例:我有一個猜數字小遊戲的程序,請寫一個程序實現在測試類中只能用5次,
     超過5次提示:遊戲試玩已結束,請付費。
package com.edu_01;
 
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
 
/**
 * 案例:我有一個猜數字小遊戲的程序,請寫一個程序實現在測試類中只能用5次,
        超過5次提示:遊戲試玩已結束,請付費。
 * 1.將文件中的鍵值對加載到集合中
 * 2.拿出已經玩耍的次數做判斷
 * 3.如果已經超過5次,提示付費
 * 4.如果少於5次開啟遊戲,將文件中的次數+1
 */
public class PropTest {
         publicstatic void main(String[] args) throws IOException {
                   //1.將文件中的鍵值對加載到集合中
                   Propertiesprop = new Properties();
                   prop.load(newFileReader("count.txt"));
                  
                   //2.拿出已經玩耍的次數做判斷
                   Stringcount = prop.getProperty("count");
                   //將String類型轉換為int類型
                   intnumber = Integer.parseInt(count);
                   if(number>4) {
                            System.out.println("次數已到,請付費");
                   }else{
                            //開啟遊戲
                            GuessNumber.startGame();
                            number++;
                            //將自增的次數重新存儲到文件中
                            prop.setProperty("count",number+"");
                            //將新的prop集合存儲到文件中
                            prop.store(newFileWriter("count.txt"), null);
                   }
         }
 
}
 
 
 
package com.edu_01;
 
import java.util.Scanner;
 
public class GuessNumber {
         publicstatic void startGame(){
                   intran = (int) (Math.random()*100+1);
                   Scannersc = new Scanner(System.in);
                   System.out.println("請輸入你猜測得數字");
                   while(true) {
                            intnumber = sc.nextInt();
                            if(number>ran) {
                                     System.out.println("大了");
                            }elseif (number<ran) {
                                     System.out.println("小了");
                            }elseif (number==ran) {
                                     System.out.println("猜對了");
                                     break;
                            }
                   }
         }
        
 
}
 
十五天:
1:多線程(理解)
         (1)線程是依賴於進程而存在的。
                   A:進程     正在運行的應用程序
                   B:線程     進程的執行路徑,執行單元
                   案例:畫圖理解單線程和多線程的代碼執行流程
                  
         (2)多線程的兩種方案:(掌握)
                   請參照:多線程兩種方式
                   繼承Thread類(查看api簡單介紹Thread類):
                   實現Runable接口:
                   packagecom.edu_02;
/**
 * 繼承Thread類(查看api簡單介紹Thread類):
 *
 */
public class MyThread extends Thread{
         //1.繼承Thread類
         //2.重寫run方法,重寫run方法中的代碼之後,當我們啟動了這個線程之後,我們的這個線程就會執行run方法中的代碼
         @Override
         publicvoid run() {
                   //需求:開啟該線程之後,執行一個for循環
                   for(int i = 0; i < 10; i++) {
                            System.out.println(i);
                   }
         }
        
}
package com.edu_02;
 
public class Test {
         publicstatic void main(String[] args) {
                   //只要我們創建了一個線程對象,並且啟動該線程的實例,我們就相當於開啟了一個線程
                   MyThreadmt = new MyThread();
                   mt.start();//1.開啟了一個線程   2.讓開啟的這個線程執行他對應的類中的run方法
                  
                   //在次創建一個子線程,並開啟這個子線程執行他的run方法
                   MyThreadmt2 = new MyThread();
                   mt2.start();
                  
         }
 
}
                  
         (3)多線程的幾個問題:
                   A:啟動線程用的是哪個方法
                            start()
                   B:start()和run()的區別
                            start():1.開啟線程  2.執行run()方法裏面的代碼
                            run():執行的是線程裏面執行的代碼,並不會開啟線程
                   C:為什麽要重寫run()
                            因為每個線程需要執行的代碼都是都是不一樣的,
                            我們需要將每個線程自己獨立執行的代碼寫到run()方法中執行
                   D:線程可以多次啟動嗎
                           
                           
         (4)線程的調度和控制
                   線程休眠(Thread.sleep(毫秒值))
                   線程名稱(setName(),getName();)
                   線程的調度及優先級setPriority(10)(註意默認值是5,區間在1-10之間)
                   什麽叫線程優先級:說白了就是設置你搶占cpu執行權搶占到的概率
                  
         (5)多線程案例(兩種方式實現,睡一會出現線程安全問題):
                   5.1繼承Thread賣票
                   5.2實現Runnable賣票(睡一會出現線程安全問題)  
                  
                   問題:
                   按照真實的情景加入了延遲,確發現出現了這樣的兩個問題:
                A:相同的票賣了多次
                         CPU的一次操作必須是原子性的(操作是CPU執行一次就可以直接完成的)
                B:出現了負數的票
                         隨機性和延遲導致的
                   出現上面的問題稱為線程安全問題。
                  
         (6)多線程安全問題
                   A:是否是多線程環境
                   B:是否有共享數據
                   C:是否有多條語句操作共享數據
                  
         (7)如何解決多線程安全問題(掌握)
                   *線程安全執行效率就低
                   A:同步代碼塊(測試不是同一個鎖的情況,測試是同一個鎖的情況)
                            synchronized(對象) {
                                     需要被同步的代碼。
                            }
                            需求:1.測試不是同一把鎖的時候線程安全嗎? 2.如果是同一把鎖線程安全嗎?
                   兩個問題:1.對象是什麽 ?
                                       答:任意對象 ,相當於是一把鎖,只要線程進去就把鎖鎖上
                                       2.需要同步的代碼?
                                       答:被線程執行的代碼
                  
                   C:鎖對象問題
                            a:同步代碼塊(定義一個抽象類,裏面專門定義一個鎖)
                                     任意對象
                           
                            b:同步方法(僅適用於實現runable接口)
                            publicsynchronized void sellTicket(){同步代碼}
                                     this
                           
                            c:靜態同步方法
                                     類的字節碼對象
                                     publicstatic synchronized void sellTicket() {
                                                        需要同步的代碼
                                     }
                                    
                                    
         (8)匿名內部類的方式使用多線程(掌握)
                   newThread() {
                            publicvoid run() {
                                     ...
                            }
                   }.start();
 
                   newThread(new Runnable(){
                            publicvoid run() {
                                     ...
                            }
                   }).start();
                  
         案例:利用匿名內部類,啟動多個線程,驗證單例設計模式之懶漢式所存在的缺陷,
               當使用多線程來搞的時候就不單例了。。
                  
         (9)JDK5的Lock鎖,我們之前造的所有的鎖都沒有手動釋放鎖
                   staticLock lock = new ReentrantLock();
                   枷鎖:lock.lock();
                   釋放鎖:lock.unlock();
                   可以讓我們明確的知道在哪裏加鎖和釋放鎖。
                   依然寫一個賣票的demo,用lock枷鎖釋放鎖,
                   為了保證我們創建的鎖一定會被釋放,用一下代碼進行改進
                   try{....}finally{.....}
        
         (10)死鎖問題
                   同步嵌套,鎖裏面套了一個鎖,出現同步嵌套
                   (簡單介紹,要求大家以後寫的時候需要註意)
                  
         (11)線程等待和喚醒機制(案例演示:waitThread,NotifyThread,MyLock,Test)
                   鎖對象調用wait()鎖對象調用notify()
                  
                   註意:
                   wait和sleep的區別
                   線程等待,在等待的同時釋放鎖,而sleep()方法在執行的過程中是不會釋放鎖的


十四、十五天筆記總結