多線程的機制是指可以同時運行多個程序塊,是程序運行的效率變的更高。
一、兩種多線程的實現方式
如果要在類裏要激活線程,必須先做好下面兩個準備:
1、線程必須擴展子Thread類,使自己成爲它的子類
2、線程的處理必須編寫在run()方法裏面
繼承Thread類來實現多線程,其基本語法如下
class 類名稱 extends Thread{
屬性...
方法...
修飾符 run(){
other code
}
}
範例1:
public class Test2 {
public static void main(String args[]){
TestThread t1 = new TestThread("A");
TestThread t2 = new TestThread("B");
t1.start();
t2.start();
}
}
class TestThread extends Thread{
private String name;
public TestThread(){
}
public TestThread(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(name + " is running");
}
}
}
運行結果:
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
B is running
A is running
通過實現Runnable接口實現多線程,基本語法如下
class 類名稱 implements Runnable{
屬性...
方法...
修飾符 run(){
other code
}
}
範例2:
public class Test3 {
public static void main(String args[]){
TestThread t1 = new TestThread("Thread A");
Thread t11 = new Thread(t1);
TestThread t2 = new TestThread("Thread B");
Thread t22 = new Thread(t2);
t11.start();
t22.start();
}
}
class TestThread implements Runnable{
private String name;
public TestThread(){
}
public TestThread(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(name + " is running");
}
}
}
運行結果:
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
Thread B is running
Thread A is running
二、Thread和Runnable的區別:
如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable接口的話,則很容易的實現資源共享
範例1:
public class Test4 {
public static void main(String args[]){
TestThread t1 = new TestThread("A");
TestThread t2 = new TestThread("B");
t1.start();
t2.start();
}
}
class TestThread extends Thread{
private String name;
private int count = 5;
public TestThread(){
}
public TestThread(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
if(count > 0){
System.out.println("count = "+count--);
}
}
}
}
運行結果:
count = 5
count = 5
count = 4
count = 4
count = 3
count = 3
count = 2
count = 2
count = 1
count = 1
沒有能夠實現資源共享,那麼用Ruannable接口呢,請看下面...........
範例2:
public class Test5 {
public static void main(String args[]){
TestThread t1 = new TestThread();
Thread t11 = new Thread(t1,"1#");
Thread t22 = new Thread(t1,"2#");
t11.start();
t22.start();
}
}
class TestThread implements Runnable{
private String name;
private int count = 5;
public TestThread(){
}
public TestThread(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
if(count>0){
System.out.println(Thread.currentThread().getName()+" count = "+count--);
}
}
}
}
運行結果:
2# count = 4
1# count = 5
2# count = 3
1# count = 2
2# count = 1
可以看出實現了資源共享
總結如下:
實現Runnable接口比繼承Thread類所具有的優勢:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。
三、線程中的一些操作方法
1、取得和設置線程的名稱
getName()
範例1:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.start();
String ThreadName = Thread.currentThread().getName();
System.out.println("Thread name is "+ThreadName);
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
System.out.println("TestThread name is "+ThreadName);
}
}
運行結果:
Thread name is main
TestThread name is Thread-0
setName()
範例2:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.setName("NewName");
mTestThread.start();
String ThreadName = Thread.currentThread().getName();
System.out.println("Thread name is "+ThreadName);
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
System.out.println("TestThread name is "+ThreadName);
}
}
運行結果:
Thread name is main
TestThread name is NewName
2、判斷線程是否啓動
isAlive()
範例3:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
System.out.println("Before start the thread:isAlive = "+mTestThread.isAlive());
mTestThread.start();
System.out.println("After start the thread:isAlive = "+mTestThread.isAlive());
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
System.out.println("TestThread name is "+ThreadName);
}
}
3、線程的強制執行
不使用join()
範例4:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.start();
for(int i=0;i<5;i++){
System.out.println("mai thread is running: "+i);
}
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
for(int i=0;i<5;i++){
System.out.println(ThreadName+" is runnging: "+i);
}
}
}
運行結果:
mai thread is running: 0
Thread-0 is runnging: 0
mai thread is running: 1
Thread-0 is runnging: 1
mai thread is running: 2
Thread-0 is runnging: 2
mai thread is running: 3
Thread-0 is runnging: 3
mai thread is running: 4
Thread-0 is runnging: 4
使用join()
範例5:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.start();
for(int i=0;i<5;i++){
if(i==2){
try{
mTestThread.join();
}catch(Exception e){
}
}
System.out.println("mai thread is running: "+i);
}
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
for(int i=0;i<5;i++){
System.out.println(ThreadName+" is runnging: "+i);
}
}
}
運行結果:
mai thread is running: 0
Thread-0 is runnging: 0
mai thread is running: 1
Thread-0 is runnging: 1
Thread-0 is runnging: 2
Thread-0 is runnging: 3
Thread-0 is runnging: 4
mai thread is running: 2
mai thread is running: 3
mai thread is running: 4
可以看到執行完join()之後,就會一直執行Thread-0
4、線程休眠
使用sleep(long millions)來進行休眠
範例6:
import java.util.Date;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.start();
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(new Date()));
for(int i=0;i<5;i++){
try{
Thread.sleep(3000);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(ThreadName+" is runnging: "+i);
System.out.println(df.format(new Date()));
}
}
}
運行結果:每隔3秒輸出一個打印
2014-05-09 11:27:51
Thread-0 is runnging: 0
2014-05-09 11:27:54
Thread-0 is runnging: 1
2014-05-09 11:27:57
Thread-0 is runnging: 2
2014-05-09 11:28:00
Thread-0 is runnging: 3
2014-05-09 11:28:03
Thread-0 is runnging: 4
2014-05-09 11:28:06
5、線程中斷
使用interrupt()方法來中斷
範例7:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
mTestThread.start();
try{
mTestThread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
mTestThread.interrupt();
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
try{
Thread.sleep(10000);
System.out.println("The thread finish sleep");
}catch(Exception e){
System.out.println("Sleep is interrupted");
return;
}
System.out.println("The thread finish normally");
}
}
運行結果:
Sleep is interrupted
6、後臺線程
對Java程序來說,只要還有一個前臺線程在運行,這個進程就不會結束,如果一個進程中只有後臺線程在運行,這個進程就會結束。前臺線程是相對後臺線程而言的。什麼樣的線程是後臺線程呢?如果某個線程對象在啓(調用start()方法)動之前調用了setDaemon(true)方法,這個線程就變成了後臺線程。
範例8:
public class Test {
public static void main(String args[]){
TestThread mTestThread = new TestThread();
TestThread2 mTestThread2 = new TestThread2();
mTestThread.setDaemon(true);
mTestThread.start();
mTestThread2.start();
}
}
class TestThread extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
while(true){
System.out.println(ThreadName+" is running");
}
}
}
class TestThread2 extends Thread{
public void run(){
String ThreadName = Thread.currentThread().getName();
for(int i=0;i<5;i++){
System.out.println(ThreadName+" is running");
}
}
}
在TestThread中的run()中使用了死循環,如果不設置setDaemon(true)方法,那麼該程序將無線循環執行下去,如果使用該方法設爲後臺進程,則運行結果如下:
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-1 is running
Thread-0 is running
Thread-0 is running
Thread-0 is running
Thread-0 is running
從以上結果我們可以看到,隨着TestThread2的結束,TestThread也會結束。
7、線程的優先級
使用setPriority()設置優先級
public class Test {
public static void main(String args[]){
Thread mTestThread1 = new Thread(new TestThread(),"A");
Thread mTestThread2 = new Thread(new TestThread(),"B");
Thread mTestThread3 = new Thread(new TestThread(),"C");
mTestThread1.setPriority(1);
mTestThread1.setPriority(2);
mTestThread1.setPriority(3);
mTestThread1.start();
mTestThread2.start();
mTestThread3.start();
}
}
class TestThread implements Runnable{
public void run(){
String ThreadName = Thread.currentThread().getName();
for(int i=0;i<5;i++){
System.out.println(ThreadName+" is running "+i);
}
}
}
運行結果:
C is running 0
A is running 0
B is running 0
A is running 1
C is running 1
A is running 2
B is running 1
B is running 2
A is running 3
C is running 2
A is running 4
B is running 3
C is running 3
B is running 4
C is running 4
並不是優先級越高就先執行,誰先執行還是取決於誰先去的CPU的資源。