12-23java面向對象之多線程

1.多線程的概念

幾乎所有的操作系統都支持同時運行多個任務,每一個任務通常就是一個程序,每個運行的程序就是一個進程。當一個程序運行是,內部可能包含了多個順序執行流,每個執行流就是線程。

繼承的特點:併發性。多個進程可以在單個處理器上併發執行,不會相互影響,

2.java多線程的實現

2.1繼承Thread

java.lang包中定義了Thread類,繼承該類之後,必須覆寫run()方法.

啓動該線程,必須調用Thread類中的start()方法,但是該方法最終還是調用的run()方法。

class MyThread extends Thread		// 繼承Thread類
{	
	private String name ;
	public MyThread(String name)	// 構造方法
	{
		this.name = name ;
	}
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "運行,i=" + i);
		}
	}
}
public class TestThread1 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("線程1") ;
		MyThread mt2 = new MyThread("線程2") ;
		mt1.run();
		mt2.run();
	}
}

運行結果發現:並沒有併發執行效果,所以要修改程序。必須使用start()方法來啓動線程。

class MyThread extends Thread		// 繼承Thread類
{	
	private String name ;
	public MyThread(String name)	// 構造方法
	{
		this.name = name ;
	}
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "運行,i=" + i);
		}
	}
}
public class TestThread2 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("線程1") ;		// 創建對象
		MyThread mt2 = new MyThread("線程2") ;
		mt1.start();
		mt2.start();
	}
}

程序運行總是併發執行不同的線程。那個線程先搶佔到CPU資源就執行它。

如果線程已經啓用了,再次調用start方法會出現異常。

class MyThread extends Thread		// 繼承Thread類
{	
	private String name ;
	public MyThread(String name)	// 構造方法
	{
		this.name = name ;
	}
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "運行,i=" + i);
		}
	}
}
public class TestThread3 
{
	public static void main(String[] args) 
	{
		MyThread mt1 = new MyThread("線程1") ;		// 創建對象	
		mt1.start();
		mt1.start();
	}
}

提示錯誤信息;

Exception in thread "main" java.lang.IllegalThreadStateException

        at java.lang.Thread.start(Unknown Source)

        at TestThread3.main(TestThread3.java:22)

2.2實現Runnable接口

Runnable接口中只定義了run()方法,所以也需要覆寫該方法。它之中並沒有start()方法,但是在Thread的構造方法中有這麼一個接收Runnable實例的,用他作爲啓動線程的操作。

Thread
public Thread(Runnable target)

class MyThread implements Runnable		// 繼承Thread類
{	
	private String name ;
	public MyThread(String name)	// 構造方法
	{
		this.name = name ;
	}
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(this.name + "運行,i=" + i);
		}
	}
}
public class TestThread4 
{
	public static void main(String[] args) 
	{
		Runnable r1 = new MyThread("線程1") ;		// 向上轉換實現接口	
		Runnable r2 = new MyThread("線程2") ;		// 向上轉換實現接口	
		Thread mt1 = new Thread(r1);
		Thread mt2 = new Thread(r2);
		mt1.start();
		mt2.start();
	}
}

執行結果:完成了多線程的功能。


2.3聯繫與區別

聯繫:定一個是Thread也是Runnable的實現,這個就是之前的代理設計。


All Implemented Interfaces:   Runnable

區別:使用Thread操作多線程無法實現資源的共享,而Runnable可以共享。同時Thread只能實現單繼承,接口可以多繼承,推薦使用Runnable

使用Runnable優點:

1、適合多個相同程序代碼的多線程處理同一個資源

2、避免單繼承

3、增強健壯性

下面驗證共享;

//本程序驗證共享屬性
class MyThread extends Thread		
{	
	private int ticket = 5;			// 定義屬性有5個
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			if (ticket > 0)
			{
				System.out.println("賣出門票ticket =" + ticket--);
			}			
		}
	}
}
public class TestThread6
{
	public static void main(String[] args) 
	{
		Thread mt1 = new MyThread();		
		Thread mt2 = new MyThread();
		mt1.start();
		mt2.start();
	}
}

這個時候發現,每個線程都各賣個的,沒有到達資源共享。

//本程序驗證共享屬性
class MyThread implements Runnable		// 實現Runnable接口
{	
	private int ticket = 5;			// 定義屬性有5個
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			if (ticket > 0)
			{
				System.out.println("賣出門票ticket =" + ticket--);
			}			
		}
	}
}
public class TestThread5 
{
	public static void main(String[] args) 
	{
		Runnable r1 = new MyThread() ;		// 向上轉換實現接口	
		Thread mt1 = new Thread(r1);		
		Thread mt2 = new Thread(r1);
		mt1.start();
		mt2.start();
	}
}

3.線程的狀態

 

調用了start也不會立即啓動,需要等待CPU

4.線程的操作方法

對線程的操作都在Thread類中。

 

4.1取得和設置線程名稱

Thread類的構造方法中有一個名稱的參數,同時具有方法setName()getName()可以分別設置和獲取名稱。線程名稱可以相同,在運行時候可以修改。

Public static Thead currentThread()方法返回當前的線程。

//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(Thread.currentThread().getName() +"當前線程名稱是—"+ i);
		}
	}
}
public class TestThread7
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();		
		Runnable mt2 = new MyThread();
		Thread t1 = new Thread(mt1);			//系統自動命名
		Thread t2 = new Thread(mt2,"線程A");			//手動命名
		t1.start() ;
		t2.start();	
	}
}


運行發現,線程設置名稱之後會按照設置名稱自動運行,沒有設置名稱的按照格式Thread-0 依次編號,實際上肯定存在static屬性,用於記錄產生對象的個數。

4.2取得當前線程

public static Thread currentThread()

Returns a reference to the currently executing thread object.

//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			System.out.println(Thread.currentThread().getName() +"當前線程名稱是—"+ i);
		}
	}
}
public class TestThread8
{
	public static void main(String[] args) 
	{
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"線程A");			//手動命名
		t2.start();
		t2.run();	
	}
}

此時程序中由主方法直接調用線程的run方法,此時main是由“t2.run();”產生的。


Java程序在啓動的時候至少有兩個線程。JVM運行的時候啓動了一個線程,在資源管理器中能夠看到,同時後臺還有垃圾收集GC線程。

4.3判斷線程是否在執行

public final boolean isAlive()
//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<3 ;++i )
		{
			System.out.println("當前線程名稱是—"+Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread9
{
	public static void main(String[] args) 
	{
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"線程A");			//手動命名
		System.out.println("線程啓動之前->" + t2.isAlive());
		t2.start();
		System.out.println("線程啓動之後->" + t2.isAlive());
		for (int i= 1;i<10 ;++i )
		{
			System.out.println(t2.isAlive());
		}
		System.out.println("代碼執行之後->" + t2.isAlive());
	}
}

由於此時在線程A和主方法中執行次序不確定,所以結果不同。

4.4線程強制運行

public final void join()                throws InterruptedException

Waits for this thread to die.

//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<40 ;++i )
		{
			System.out.println("當前線程名稱是—"+ Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread10
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		t1.start();
		for (int i =0;i<40 ;++i )
		{
			if (i>10)
			{
				try
				{
					t1.join();
				}
				catch (InterruptedException e)
				{
				}
			}
			System.out.println("main運行" + i);
		}
	}
}


main運行到10之後,都是由主線程佔用。

4.5線程的休眠

public static void sleep(long millis)  使用類名稱調用,類似current                  throws InterruptedException

//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i =0;i<10 ;++i )
		{
			try
			{
				Thread.sleep(2000);			// 每2s產生一個輸出
			}
			catch (InterruptedException e)
			{
			}
			System.out.println("當前線程名稱是—"+ Thread.currentThread().getName() + i);
		}
	}
}
public class TestThread11
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		t1.start();
	}
}

4.6線程強制中斷

當一個線程正在運行時,另一個線程可以使用interrupt方法中斷其運行。

public void interrupt()

Interrupts this thread.

//本程序測試線程名稱
class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		System.out.println("1.進入run方法");
		try
		{
			Thread.sleep(5000);			// 休眠5s
			System.out.println("2.休眠結束");
		}
		catch (InterruptedException e)
		{
			System.out.println("3.休眠中斷");
			return ;		// 返回調用處
		}
		System.out.println("4.run正常結束");
	}
}
public class TestThread12
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		t1.start();
		try  //作用是延時
		{
			Thread.sleep(2000);			
		}
		catch (InterruptedException e)
		{}
		t1.interrupt();
	}
}

4.7後臺線程

一個線程在運行,整個java進程不會消失。可以設置後臺線程,哪怕進程結束了,線程還在。

public final void setDaemon(boolean on)

class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		while (true)
		{
			System.out.println(Thread.currentThread().getName() + "在運行");
		}
	}
}
public class TestThread13
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		t1.start();
		t1.setDaemon(true);
	}
}

4.8優先級設置

public final void setPriority(int newPriority)

Changes the priority of this thread.

<p>注意:主方法的優先級是<span style="font-family:Times New Roman;">5</span></p><h2>4.9<span style="font-family:黑體;">線程的禮讓</span></h2><table><tbody><tr><td valign="top"><p>public static void yield()</p><p>Causes the currently executing thread object to temporarily pause and allow other threads to execute.</p></td></tr></tbody></table>class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i=0;i<3 ;++i )
		{
			try
			{
				Thread.sleep(1000);			
				System.out.println("正在運行的是: " + Thread.currentThread().getName() + i);
			}
		catch (InterruptedException e){}
		}
	}
}
public class TestThread14
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"線程B");			//手動命名
		Runnable mt3 = new MyThread();
		Thread t3 = new Thread(mt3,"線程C");			//手動命名
		t1.setPriority(Thread.MAX_PRIORITY);							//設置優先級
		t2.setPriority(Thread.MIN_PRIORITY);
		t3.setPriority(Thread.NORM_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
	}
}

注意:主方法的優先級是5

4.9線程的禮讓

public static void yield()

Causes the currently executing thread object to temporarily pause and allow other threads to execute.

class MyThread implements Runnable
{	
	public void run()				// 覆寫run方法
	{
		for (int i=0;i<5 ;++i )
		{
			System.out.println("正在運行的是: " + Thread.currentThread().getName() + i);
			if (i ==3)
			{
				System.out.println("線程禮讓");
				Thread.currentThread().yield();
			}
		}
	}
}
public class TestThread15
{
	public static void main(String[] args) 
	{
		Runnable mt1 = new MyThread();
		Thread t1 = new Thread(mt1,"線程A");			//手動命名
		Runnable mt2 = new MyThread();
		Thread t2 = new Thread(mt2,"線程B");			//手動命名
		t1.start();
		t2.start();
	}
}


祝大家健健康康,快快樂樂。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章