進程:程序的一次動態加載過程,包括了代碼加載,編譯,執行,結束的一個完整過程
線程:線程是比進程更小的單位,行爲很像進程,一個進程在執行過程中可以產生多個線程
多線程序機制:每個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();
}
}