1.通過繼承Thread類創(chuàng)建線程
public class Thread extends Object implements Runnabel
- Thread類已經(jīng)實(shí)現(xiàn)了Runnable接口
- 繼承Tread的類只需重寫run方法
- Thread類已經(jīng)定義了final類型的getName和setName方法
- 啟動線程應(yīng)調(diào)用start方法而不是run方法
- 一個線程對象只能調(diào)用一次start方法,否則會拋IllegalThreadStartException錯誤
package com.gyp.thread.start;
public class Test1 extends Thread{
private String name;
public Test1(){
}
public Test1(String name){
setName(name);
}
public void run(){
for(int i=0;i<10;i++){
System.out.println("當(dāng)前運(yùn)行的線程:"+getName()+",i="+i);
}
}
public static void main(String[] args){
Test1 t1 = new Test1();
Test1 t2 = new Test1("線程2");
t1.start();
t2.start();
//受單繼承的影響
// t2.start();
}
}
2.通過實(shí)現(xiàn)Runnable接口創(chuàng)建線程
public interface Runnable{ public abstract void run(); }
- Runnable只提供了run方法
- Runnable對線程沒有任何支持局装,在獲得線程實(shí)例后必須通過Thread類的構(gòu)造函數(shù)來實(shí)現(xiàn)
package com.gyp.thread.start;
public class Test2 implements Runnable {
private String name;
//實(shí)現(xiàn)接口的類要自己定義方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Test2(){
}
public Test2(String name){
setName(name);
}
public void run(){
for(int i=0;i<10;i++){
System.out.println("當(dāng)前運(yùn)行的線程:"+getName()+",i="+i);
}
}
public static void main(String[] args){
Test2 r1 = new Test2();
Test2 r2 = new Test2("線程2");
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
2.5繼承Thread類和實(shí)現(xiàn)Runnable接口的區(qū)別
- 一般選擇后者
- 避免單繼承帶來的局限性
- 適合多個相同程序代碼的線程區(qū)處理同一資源的情況峻汉。
- 前者處理同一資源可用靜態(tài)變量善延。
3.主線程-main()
- 主線程是自動創(chuàng)建的锐朴,是產(chǎn)生應(yīng)用程序所有其他線程的線程。
- 程序中只要還有其他非守護(hù)線程沒有結(jié)束个盆,主線程就不會結(jié)束假抄,即使主線程已執(zhí)行完或者調(diào)用了retuen。
- 一個java程序最少有兩個線程踏志,一個是main,優(yōu)先級5阀捅,一個是JVM垃圾收集線程
package com.gyp.thread.start;
public class Test3 implements Runnable {
public void run(){
for(int i=0; i<10; i++){
System.out.println("當(dāng)前運(yùn)行線程:"+Thread.currentThread()+", i="+i);
}
}
public static void main(String[] args){
//獲取當(dāng)前對象的線程引用
Thread mi = Thread.currentThread();
System.out.println("線程的信息:"+mi);
System.out.println("線程的名字:"+mi.getName());
mi.setName("主線程");
System.out.println("線程的名字:"+mi.getName());
Test3 r = new Test3();
Thread t = new Thread(r);
t.start();
t.run(); //直接調(diào)用run方法
}
}
4.線程的加入join()
使當(dāng)前運(yùn)行的線程停下來,等待調(diào)用join的線程執(zhí)行针余,可設(shè)最長等待時(shí)間饲鄙,也可不設(shè)等他執(zhí)行完凄诞。
package com.gyp.thread.start;
import java.util.Date;
/**
* @author gyp19
* 線程的加入join()
* 等待調(diào)用的線程終止
*/
class ThreadTest4 implements Runnable{
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<5;i++){
System.out.println("當(dāng)前運(yùn)行的線程:"+Thread.currentThread().getName()+" ,i="+i+"時(shí)間:"+new Date());
}
}
}
public class Test4 {
public static void main(String[] arge){
ThreadTest4 r = new ThreadTest4();
Thread t = new Thread(r,"線程一");
Thread mi = Thread.currentThread();//獲得主線程的引用
t.start();
for(int i=0;i<10;i++){
if(i==5){
try {
t.join(3000); //最大等待時(shí)間3s
// mi.join(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main="+i+",時(shí)間:"+new Date());
}
}
}
5.線程的喚醒 interrupt()
線程從休眠的組賽狀態(tài)(sleep)轉(zhuǎn)化為運(yùn)行狀態(tài)忍级。
package com.gyp.thread.start;
import java.util.Date;
class ThreadTest5 implements Runnable{
public void run(){
System.out.println("線程開始的時(shí)間:"+new Date());
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("線程被喚醒啦啦啦");
}
System.out.println(Thread.currentThread().getName()+"的第"+i+1+"秒"+", 時(shí)間:"+new Date());
}
System.out.println("線程的結(jié)束時(shí)間:"+new Date());
}
}
public class Test5 {
public static void main(String[] args){
ThreadTest5 r = new ThreadTest5();
Thread t = new Thread(r,"線程一");
t.start();
try {
Thread.sleep(2000);//使用t.sleep(2000);的效果也是一樣一樣的
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt(); //喚醒線程
}
}
6.后臺線程
- 后臺執(zhí)行的線程帆谍,也可稱之為守護(hù)線程。
- JVM垃圾回回收線程就是典型的守護(hù)線程轴咱。
- 后臺線程為其他線程服務(wù)汛蝙,當(dāng)所有非后臺線程結(jié)束時(shí)后臺線程才結(jié)束。
- main()是一個非后臺線程朴肺。
setDaemon(true) : 設(shè)置后臺線程
isDaemon() : 判斷是否為后臺線程窖剑,是則true
package com.gyp.thread.start;
public class Test6 implements Runnable{
public void run(){
int i=0;
while(true){
System.out.println("i="+(i++));
}
}
public static void main(String[] args){
Test6 r = new Test6();
Thread t = new Thread(r,"線程一");
t.setDaemon(true);
if(t.isDaemon()){
t.start();
}
System.out.println("say something");
}
}
7.線程的禮讓
1.當(dāng)前正在運(yùn)行的線程推出運(yùn)行狀態(tài),暫時(shí)讓其他線程執(zhí)行戈稿。
2.不能讓給指定的線程西土,一般優(yōu)先級高的線程會先當(dāng)?shù)竭\(yùn)行資源。
3.sleep和yield的區(qū)別
- sleep讓出運(yùn)行權(quán)時(shí)不考慮別的線程的優(yōu)先級鞍盗。
- sleep轉(zhuǎn)到堵塞狀態(tài)需了,yield轉(zhuǎn)到就緒狀態(tài)。
- sleep會拋出異常般甲。
- slepp有著更好的移植性援所,不能依靠yield方法提高程序的并發(fā)性。
yield() : 調(diào)用禮讓
package com.gyp.thread.start;
class ThreadDemo1 implements Runnable{
public void run(){
for(int i=0;i<10;i++){
System.out.println("禮讓->"+Thread.currentThread().getName()+":i="+i);
//線程的禮讓
Thread.currentThread().yield();
}
}
}
class ThreadDemo2 implements Runnable{
public void run(){
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+":i="+i);
}
}
}
public class Test7 {
public static void main(String[] args){
Runnable r1 = new ThreadDemo1();
Runnable r2 = new ThreadDemo2();
Thread t1 = new Thread(r1,"Thread-one");
Thread t2 = new Thread(r2,"線程二");
t1.start();
t2.start();
}
}