1、線程的基本概念
例子:
分析:
2、線程的創建和啟動
第一種線程的創建:
????定義一個線程類來實現Runner接口
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {Runner1 runner1 = new Runner1();Thread myThread = new Thread(runner1);myThread.start();//這行注釋掉的話,線程就不會執行。for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class Runner1 implements Runnable{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
運行結果:
我們會發現,主線程,和子線程是交替執行的。
但是呢,要注意:
但是若是直接調用run方法,是方法調用,兩者之間天壤之別,只有執行完成一個才會去執行另一個。
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {Runner1 runner1 = new Runner1();//Thread myThread = new Thread(runner1);runner1.run();//myThread.start();//這行注釋掉的話,線程就不會執行。for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class Runner1 implements Runnable{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
證明如下:
第二種線程的創建:
定義一個Thread的子類并重寫其run方法。
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class MyThread extends Thread{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
此時,已經新建一個MyThread類繼承自Thread類,所以就不用new一個Thread 的對象出來了,而只需要new一個MyThread的子對象。然后調用其start()方法。
執行結果:
我們發現和第一種創建線程的結果是一樣的,也是交替執行。但是兩個線程分得到的時間片并不一定是相同的。
兩個方式有什么區別呢?繼承Thread類的方式(第二種方式)比較死,只能從一個類繼承,第一種方式呢?比較靈活實現接口,還可以從其他類繼承。只要能實現接口,就不要從Thread類繼承。
線程狀態轉換:
1、sleep方法:
package com.zhj.www;import java.util.*;public class TestInterrupt {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();try {Thread.sleep(10000);//主線程睡眠}catch (InterruptedException e) {}//thread.interrupt();//睡著的時候打斷,太粗暴了//為什么不用它呢?thread.flag = false;}
}class MyThread extends Thread{boolean flag = true;public void run() {while(flag) {System.out.println("==="+new Date()+"===");try {sleep(1000);} catch (InterruptedException e) {return;}}}
}
運行結果:
2、join方法:
栗子:
package com.zhj.www;public class TestJoin {public static void main(String[] args) {MyThread2 t1 = new MyThread2("abcdef");t1.start();try {t1.join();//合共}catch (InterruptedException e) {}for(int i = 1;i<=10;i++) {System.out.println("I am main thread");}}
}
class MyThread2 extends Thread{public MyThread2(String s) {super(s);}public void run() {for(int i = 0; i<=10;i++) {System.out.println("I am "+ getName()+" (i:)"+i);try {sleep(1000);} catch (InterruptedException e) {return;}}}
}
運行結果:
3、yield方法:
package com.zhj.www;import java.util.*;public class TestYield {public static void main(String[] args) {MyThread3 t1 = new MyThread3("t1");MyThread3 t2 = new MyThread3("t2");t1.start();t2.start();}
}class MyThread3 extends Thread{MyThread3(String s) {super(s);}public void run() {for (int i = 1; i <= 100; i++) {System.out.println(getName()+": "+i);if(i%10 == 0) {yield();}}}
}
運行結果:
t1到10的倍數切換t2,t2到10的倍數切換t1;
上例子:
package com.zhj.www;public class TestPriority {public static void main(String[] args) {Thread t1 = new Thread(new T1());Thread t2 = new Thread(new T2());t1.setPriority(Thread.NORM_PRIORITY+3);//t1得到的執行時間長t1.start();t2.start();}
}
class T1 implements Runnable{public void run() {for(int i =0;i< 100;i++) {System.out.println("T1: "+ i);}}
}
class T2 implements Runnable{public void run() {for(int i =0;i< 100;i++) {System.out.println("-------T2: "+ i);}}
}
運行一下:
可以發現:t1比t2運行的時間長。
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
額外的栗子:
--------------------------------------------------------------------------------------
TestThread2.java
package com.zhj.www;public class TestThread2 {public static void main(String[] args) {Runner2 r = new Runner2();Thread t1 = new Thread(r);Thread t2 = new Thread(r);t1.start();t2.start();}
}class Runner2 implements Runnable{public void run() {for(int i = 0; i <= 30; i++) {System.out.println("No: "+ i);}}
}
運行一下:
TestThread3.java
package com.zhj.www;public class TestThread3 {public static void main(String[] args) {Runner3 runner3 = new Runner3();Thread thread = new Thread(runner3);thread.start();}
}
class Runner3 implements Runnable {public void run() {for(int i = 0; i<30;i++) {if(i%10 == 0 && i != 0) {try {Thread.sleep(2000);} catch (InterruptedException e) {}}System.out.println("No. " + i);}}
}
當i 是 10的倍數時,會睡眠2s。
運行結果:
TestThread4.java
package com.zhj.www;public class TestThread4 {public static void main(String[] args) {Runner4 r = new Runner4();Thread t = new Thread(r);t.start();for(int i = 0; i< 100000 ; i++) {if(i%10000 == 0 & i>0) {System.out.println("in thread main i =" + i);} }System.out.println("Thread mian is over");r.shutDown();}
}class Runner4 implements Runnable{private boolean flag = true;public void run() {int i = 0;while(flag == true) {System.out.println(" " + i++);}}public void shutDown() {flag = false;}
}
主要:怎么讓一個正常執行的線程停止。
run方法結束,線程就結束。
運行結果:
TestThread5.java(關于join方法)
package com.zhj.www;public class TestThread5 {public static void main(String[] args) {Runner5 r = new Runner5();Thread thread = new Thread(r);thread.start();try {thread.join();}catch (InterruptedException e) {}for(int i = 0; i<50;i++) {System.out.println("主線程:"+ i);}}
}
class Runner5 implements Runnable{public void run(){for(int i= 0 ;i<50;i++) {System.out.println("SubThread: " + i);}}
}
運行結果:
TestThread6.java
package com.zhj.www;public class TestThread6 {public static void main(String[] args) {Thread thread = new Runner6();thread.start();for(int i = 0; i<50 ;i++) {System.out.println("MainThread: "+ i);}}
}class Runner6 extends Thread{public void run() {System.out.println(Thread.currentThread().isAlive());for(int i = 0;i<50;i++) {System.out.println("SubThread: " + i);}}
}
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
線程同步
自身是一個線程類。
分析內存:
分析完內存,我們運行一下:
package com.zhj.www;public class TestSync implements Runnable{Timer timer =new Timer();public static void main(String[] args) {TestSync testSync = new TestSync();Thread t1 = new Thread(testSync);Thread t2 = new Thread(testSync);t1.setName("t1");t2.setName("t2");t1.start();t2.start();}public void run() {timer.add(Thread.currentThread().getName());}
}class Timer{private static int num = 0;public void add(String name ) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"個使用timer的線程");}
}
運行一下:
結果為什么是這樣呢?感覺哪里不對。
線程在執行這個方法時,被另一個線程打斷了。寫sleep,是為了
放大這個效果。
怎么解決呢?
在執行的時候,鎖定當前對象。一個執行進入到鎖住區域時,另一個
線程不可打擾。
如下:
public void add(String name ) {synchronized (this) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"個使用timer的線程");}}
互斥鎖。
另外簡便的寫法:
public synchronized void add(String name ) {//synchronized (this) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"個使用timer的線程");//}}
執行這個方法時,鎖住當前對象。
睡著的時候,依然抱著這把鎖,其他的人如果要執行這個方法必須等他執行完這個方法。