程式.程序(Process).線程(Thread)
在作業系統中運作的程式就是程序,程式是代碼,是死的,是一個靜态的概念,而程序是執行程式的一次執行過程,是一個動态的概念,是系統資源配置設定的機關,比如QQ,LOL,IDE等等。。
一個程序可以有多個線程,如在看視訊時,可以同時聽聲音,看圖像,看彈幕,等等。
即使一個程序什麼都不幹,裡面也有一個main線程(主線程) ,線程就是獨立的執行路徑。
注意:很多多線程是模拟出來的,真正的多線程是隻有多個CPU,即多核,如 伺服器。而模拟出來的多線程在一個CPU下,同一時間隻執行一個代碼,隻是切換的很快而已。
建立線程之一:
繼承Thread (不建議使用,避免OOP單繼承局限性)
- 自定義線程類繼承Thread類
- 重寫run()方法,編寫線程執行體
- 建立線程對象,調用start()方法啟動線程
執行個體如下:
public class TestThread1 extends Thread {
@Override
public void run() {
super.run();
//run方法線程體
for (int i = 0; i < 20; i++) {
System.out.println("run線程。。。。");
}
}
public static void main(String[] args) {
//main線程,主線程
//建立線程對象,調用start方法開啟線程
TestThread1 testThread1 = new TestThread1();
testThread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("main......");
}
}
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TP31ENBRkTysGVOBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0YTM5ATNzETM3ADNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
注意:線程開啟不一定立即執行,由cpu排程執行。調用多個線程對象的start()方法,執行順序是不一定的。
用多線程下載下傳圖檔
下載下傳一個commons IO包,他是别人針對開發IO流功能的工具類庫,直接百度搜尋即可,将其拷到項目裡的一個建立檔案夾裡,此時他不能直接用,要右鍵此檔案夾選中Add as Library添加到庫裡面。此時如果檢視項目資源目錄,裡面就有一個libraries。
1.先寫一個下載下傳器,裡面有一個下載下傳方法,它是通過FileUtils這個工具類的copyURLToFile方法将圖檔下載下傳下來。
//下載下傳器,因為這個定義的類全都放在了一個頁面是以沒有public,一個java類中隻能有一個public class類
class WebDownLoader{
public void downLoader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));//此方法是把網絡上的一個網頁位址變成一個檔案
}catch (IOException e){
e.printStackTrace();
System.out.println("IO異常,dowmloader方法出現問題");
}
}
}
2.要實作一個線程類,然後寫一個有參構造,用來丢入位址和名字,再然後重寫run()方法,它是下載下傳圖檔線程的執行體。最後在main()函數中通過三個構造器建立三個線程,然後用三個start()方法把這三個線程同時啟動起來。
public class TextThread2 extends Thread{
private String url;//網絡圖檔位址
private String name;//儲存的檔案名
public TextThread2(String url,String name){ //寫構造器
this.url=url;
this.name=name;
}
@Override
public void run() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,name);
System.out.println("下載下傳了檔案名為:"+name);
}
public static void main(String[] args) {
TextThread2 t1=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
TextThread2 t2=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
TextThread2 t3=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
t1.start();
t2.start();
t3.start();
}
}
建立線程方法二:
實作Runnable(推薦該方式)可避免單繼承局限性,靈活,友善同一個對象被多個線程使用
- 定義MyRunnable類實作Runnable接口
- 重寫run()方法,編寫線程執行體
- 建立線程對象,調用start()方法啟動線程
執行個體如下:
和繼承Thread類那種方法差不多,這就是将Runable接口的實作類對象丢入Thread裡面,調用start()啟動.
public class TextThread3 implements Runnable {
@Override
public void run() {
//run()方法線程體
for (int i = 0; i < 200; i++) {
System.out.println("run"+i);
}
}
public static void main(String[] args) {
//建立runnable接口的實作類對象
TextThread3 textThread3 = new TextThread3();
//建立線程對象,通過線程對象來開啟我們的線程,代理
Thread thread = new Thread(textThread3);
thread.start();
//這兩句等價于 new Thread(testThread3).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
}
}
}
用runnable多線程下載下傳圖檔
和第一種方式比較隻需改動兩處——畫“***************************”處
public class TextThread2 implements Runnable{ ***************************************
private String url;//網絡圖檔位址
private String name;//儲存的檔案名
public TextThread2(String url,String name){ //寫構造器
this.url=url;
this.name=name;
}
@Override
public void run() {
WebDownLoader webDownLoader = new WebDownLoader();
webDownLoader.downLoader(url,name);
System.out.println("下載下傳了檔案名為:"+name);
}
public static void main(String[] args) {
TextThread2 t1=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
TextThread2 t2=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
TextThread2 t3=new TextThread2("此處寫要下載下傳圖檔的位址","給想要下載下傳的圖檔命名");
new Thread(t1).start(); **************************************
new Thread(t2).start(); **************************************
new Thread(t3).start(); **************************************
}
}
//下載下傳器
class WebDownLoader{
public void downLoader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url), new File(name));//此方法是把網絡上的一個網頁位址變成一個檔案
}catch (IOException e){
e.printStackTrace();
System.out.println("IO異常,dowmloader方法出現問題");
}
}
}
一個對象被多個線程使用的執行個體:
//多個線程同時操作一個Runnable接口的對象
//買火車票的例子
public class TestThread4 implements Runnable{
//票數
private int ticketNums = 10;
@Override
public void run() {
while(true){
if(ticketNums<=0){
break;
}
//模拟延時,200毫秒,0.2秒
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--+"票");
}
}
public static void main(String[] args) {
//一個資源
TestThread4 testThread4 = new TestThread4();
//多個代理
new Thread(testThread4,"小紅").start();
new Thread(testThread4,"小白").start();
new Thread(testThread4,"小黑").start();
}
}
多線程龜兔賽跑
public class Race implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子")&&i%10==0) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag = gameOver(i);
if (flag) {
break;
}
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
}
}
//判斷是否完成比賽
private boolean gameOver(int steps) {
//判斷是否有勝利者
if (winner != null) {
return true;
} else if (steps >= 100) {
//Thread.currentThread()這是Theard類的currentThread()方法,意思就是”目前線程“
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
return true; }
else {
return false;
}
}
public static void main(String[] args) {
Race race = new Race();
//由于兩個線程公用一個資源,都用run方法,誰先跑完執行方法裡面的break,另一個也就跑不了了
new Thread(race,"兔子").start();
new Thread(race,"烏龜").start();
}
}