Java多線程機制

進程:程序的一次動態加載過程,包括了代碼加載,編譯,執行,結束的一個完整過程
線程:線程是比進程更小的單位,行爲很像進程,一個進程在執行過程中可以產生多個線程
關係

多線程序機制:每個java程序都有一個主線程,當jvm加載代碼,發現main方法,此時就會啓動主線程,在mian方法執行過程中再創建的線程就是其他線程。

線程的四種狀態:
新建狀態:Thread類被創建
運行狀態:執行run()方法
中斷狀態:

  • 1.資源從當前線程被切換給了其他線程
  • 2.調用sleep()方法
  • 3.wait()方法
  • 4 .線程執行某個操作期間進入了阻塞狀態

死亡狀態:1.正常運行完全部工作 2.被強制中斷

狀態圖:
在這裏插入圖片描述
java線程的優先級在常數1-10之間,默認爲5級

創建線程的三種方法:

1.線程任務類,接口Runnable

public class ThreadB implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(i+"B線程");
		}
	}
}

啓動線程時,需要通過Thread 對象進行啓動

public class ThreadTestB {

	public static void main(String[] args) {
		//1.創建線程任務
		ThreadB tb=new ThreadB();
		//2.通過線程任務,創建線程對象
		Thread t=new Thread(tb);
		t.start();
		for(int i=0;i<10;i++) {
			System.out.println(i+"Main線程");
		}
	}

}

2.繼承Thread的線程類

public class ThreadTestA {

	public static void main(String[] args) {
		//1.創建線程對象
		ThreadA ta=new ThreadA();
		ta.start();
		for(int i=0;i<10;i++) {
			System.out.println(i+"Main線程");
		}
	}

}

啓動線程時,直接 new 線程對象.start()方法

public class ThreadA extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(i+"A線程");
		}
	}
}

線程同步(synchronized)

問題:當兩個或多個線程同時訪問同一變量時,並且對該變量會進行修改,那麼就可能會出現混亂
線程同步方法:使用 synchronized 修飾來方法
線程同步機制:當一個線程A使用synchronized方法時,其他線程想用synchronized方法時就必須等待,直到線程A使用完synchronized方法。

例子:會計和出納共同擁有一個賬本,他們都可以使用saveOrTake方法對賬本進行訪問。如果會計正在使用saveOrTake存入錢時,出納被禁止使用,反之如此。

package com.money;
//線程同步(synchronized):
public class Test {

	public static void main(String[] args) {
		Bank bank = new Bank();
		bank.setMoney(300);
		Thread accountant = new Thread(bank); //聲明線程變量會計
		Thread cashier = new Thread(bank); //聲明線程變量出納
		accountant.setName("accountant");
		cashier.setName("cashier");
		accountant.start();
		cashier.start();
	}

}
package com.money;

public class Bank implements Runnable {
	int money = 200;
	public void setMoney(int n) {
		money = n;
	}
	
	public void run() {
		if(Thread.currentThread().getName().equals("accountant")) {
			saveOrTake(300);
		}else if(Thread.currentThread().getName().equals("cashier")) {
			saveOrTake(150);
		}
	}

	//存取方法  (如果將synchronized取掉,線程就不會有等待,結果將會不一樣)
	public synchronized void saveOrTake(int amount) {
		if(Thread.currentThread().getName().equals("accountant")) {
			for(int i=1;i<=3;i++) {
				money=money+amount/3;   //每次存入100,暫停一下
				System.out.println(Thread.currentThread().getName()+
						"存入"+amount/3+"元,賬上有"+money+"元");
			}
			try {
				Thread.sleep(1000);    //此時出納無法使用saveOrTake方法
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		else if(Thread.currentThread().getName().equals("cashier")) {
			for(int i=1;i<=3;i++) {
				money=money-amount/3;   //每次取出50,暫停一下
				System.out.println(Thread.currentThread().getName()+
						"取出"+amount/3+"元,賬上有"+money+"元");
			}
			try {
				Thread.sleep(1000);   //此時會計無法使用saveOrTake方法
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
}

在這裏插入圖片描述


協調同步的線程(wait)

問題:當一個線程使用同步方法後,其他線程就必須等待,直到當前線程使用完該方法。同步方法特殊情況。
方法:當一個線程中在使用的同步方法時,需要用到其中的某個變量,而此變量又需要其他線程修改後才符合此線程的需要,此時就需要用wait()方法。
wait()方法:中斷線程的執行,使當前線程等待,允許其他線程使用這個同步方法。使用完後通過線程結束等待:notify(),notifyall()

例子:A和B買電影票,電影票5元一張,售票員只有兩張5元的錢,A有20元排第一位,B有5元排第二位。因此A必須等待B先買票。

package com.ticket;

public class Test {
	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		Thread A = new Thread(ticket);
		Thread B = new Thread(ticket);
		A.setName("A");
		B.setName("B");
		A.start();
		B.start();
	}
}
package com.ticket;

public class Ticket implements Runnable {
	int five=2;
	int twenty=0;
	@Override
	public void run() {
		if(Thread.currentThread().getName().equals("A")) {
			saleTicket(20);
		}else if(Thread.currentThread().getName().equals("B")) {
			saleTicket(5);
		}
	}
	
	public synchronized void saleTicket(int money) {
		if(money==5) {
			five=five+1;
			System.out.println(Thread.currentThread().getName()+"拿到入場票");
		}else if(money==20) {
			while(five<3) {  //如果5元少於3張則需要等待
				try {
					System.out.println(Thread.currentThread().getName()+"等待買票");
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			five=five-3;
			twenty=twenty+1;
			System.out.println(Thread.currentThread().getName()+"拿到入場票,收到15元找零");
		}
		notifyAll();
	}
}

在這裏插入圖片描述

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