------- android教育訓練、java教育訓練、期待與您交流! ----------
黑馬學習日志之九 多線程
1 線程
程序:一個正在執行的程式,每個程序執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元。
線程:程序中的一個獨立的控制單元,就是程序中的一個子程式,一個獨立的執行路徑。線程控制程序的執行。
主線程:JVM啟動時會有一個程序Java.exe,該程序中至少有一個線程負責Java.exe 執行,這個線程運作代碼存在于main方法中,該線程稱為主線程。
更細節說明JVM,JVM不止一個線程,還有負責垃圾回收機制的線程。
注意:因為多個線程都擷取cpu的執行權。cpu執行到誰,誰就運作。明确一點,在某一個時刻,隻能有一個程式在運作。(多核除外)cpu在做着快速的 切換,以達到看上去是同時運作的效果。我們可以形象把多線程的運作行為在互相搶奪cpu的執行權。這就是多線程的一個特性:随機性。誰搶 到誰執行,至于執行多長,cpu說的算。
2 建立線程
建立線程,繼承Thread類
建立線程方法一:将類聲明為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。
(1)自定義類繼承Thread類
(2)重寫run方法
(3)将要執行的代碼寫在run方法中
(4)建立Thread類的子類對象
(5)調用start方法開啟線程。
為什麼要覆寫run()方法:Thread類用于描述線程,該類就定義了一個功能,用于存 儲線程要運作的代碼,該存儲功能就是run方法。也就是 說Thread類中的run方法用于存儲線程要運作的方法。
例子:
// 自定義建立線程
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("這是線程中的方法!");
}
}
// 主線程
public static void main(String[] args) {
MyThread mythread = new MyThread();
mythread.start(); // 必須start()啟動線程
for (int i = 0; i < 1000; i++) {
System.out.println("這是主函數的方法!");
}
}
建立線程方法二:實作Runable接口
(1)定義類實作Runable接口
(2)覆寫Runable接口中的run方法
(3)通過Thread類建立線程對象
(4)将Runable接口的子類對象作為實參傳遞給Thread類的構造函數。
(5)調用Thread類的start方法,開啟線程
為什麼要将Runnable接口的子類對象傳遞給Thread的構造函數:
因為,自定義的run方法所屬的對象是Runnable接口的子類對象。
是以要讓線程去指定指定對象的run方法。就必須明确該run方法所屬對象。
例子:
// 自定義建立線程
class MyThread implement Runable {
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("這是線程中的方法!");
}
}
// 主線程
public static void main(String[] args) {
MyThread m = new MyThread();
Thread t = new Thread(m);
m.start()// 必須start()啟動線程
for (int i = 0; i < 1000; i++) {
System.out.println("這是主函數的方法!");
}
}
3 實作方式和繼承方式的差別
實作方式好處:避免了單繼承的局限性。在定義線程時,建議使用實作方式。
兩種方式差別:
繼承Thread:線程代碼存放Thread子類run方法中。
實作Runnable,線程代碼存在接口的子類的run方法。
4 匿名線程
(1)繼承Thread類用匿名内部類實作
new Thread(){
public void run(){
for(int i = 0; i <1000; i++){
System.out.println("這是匿名線程實作,匿名的是線程");
}
}
}.start();
(2)實作Runnable接口用匿名内部類實作
new Thread(new Runnable(){
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("匿名線程,匿名的是Runnable!");
}
}
}).start();
例子:
買車票問題:
class Ticket implements Runnable
{
private int tick = 1000;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(tick>0)
{
//try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
}
}
}
}
}
class TicketDemo2
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
5 Thread類常用方法
currentThread():靜态方法,用來擷取目前線程
getName()、setName():用來擷取、設定目前線程的名字
Sleep(毫秒)控制線程休眠,機關為毫秒
setDeamon(true):将線程設定為守護線程。該線程不會單獨執行。
join:目前線程暫停,等待加入的線程運作結束,目前線程繼續執行
setPriority(int newPriority):更改線程優先級
yield():暫停目前線程對象,執行其他線程
6 多線程的安全問題
當多條語句在操作同一個線程共享資料時,一個線程對多條語句隻執行了一部分,還沒執行完,另一個程序就參與進來執行,導緻共享資料的錯誤。
解決辦法:對多條操作共享資料的語句,隻能讓一個線程執行完。在執行過程中,其他線程不能參與執行。
防止cpu的随機性,由于不同的線程切換,輸出錯亂的結果,是以要對程式進行同步,當進行同步的時候,cpu必須将該線程中的程式全部輸出,執行完全,才會執行别的的程式。
線程同步前提:必須要有兩個或兩個以上的線程;必須是多個線程使用同一個鎖。
必須保證同步中隻能有一個線程在運作。
同步代碼塊 使用synchronized關鍵字加上一個鎖對象來定義一段代碼
synchronized(鎖對象){}
同步函數 使用synchronized進行修飾。
非靜态同步方法預設使用目前對象this作為鎖對象。
例子:
public class DemoSynchronized {
public static void main(String[] args) {
Test t = new Test();
new Thread() {
public void run() {
while(true) {
t.test1();
}
}
}.start();
new Thread() {
public void run() {
while(true) {
t.test2();
}
}
}.start();
}
}
class Test {
public void test1() {
synchronized(this){//鎖對象可以是任意對象,但是要保證鎖對象一緻
System.out.print("一");
System.out.print("二");
System.out.print("三");
System.out.print("四");
}
}
public synchronized void test2() {//同步函數的鎖對象是this
{
System.out.print("1");
System.out.print("2");
System.out.print("3");
System.out.print("4");
}
}
靜态同步函數
同步函數被靜态修飾後,鎖不再是this,因為靜态方法中不可以定義this。
靜态進記憶體時,記憶體中沒有本類對象,但是一定有該類對應的位元組碼檔案*.class.
靜态同步方法的鎖是該方法所在類的位元組碼檔案對象 類名.class
例子:
Class Single
{
private staticSingles=null;//注意此處 不可以加final來修飾 因為此處s指向是空 如果是final修飾的話表示最終指向空 是不可以的
private Single(){}
public static Single getIntance(){
if(s == null){
synchronized(Single.class){ //此處是靜态函數 是以用class
if(s ==null)
s=new Single();
}
}
returns;
}
}
------- android教育訓練、java教育訓練、期待與您交流! ----------