1. 程式人生 > 實用技巧 >第七章 多執行緒

第七章 多執行緒

7.1、概述

程序:是正在執行的程式

執行緒:是程序中的單個順序控制流,是一條執行路徑

7.2、實現方式

7.2.1、方式一

class MyThread extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}

public class Main {
	public static void main(String[] args) {
		MyThread my1 = new MyThread();
		MyThread my2 = new MyThread();
		my1.setName("執行緒一");
		my2.setName("執行緒二");
		my1.start();
		my2.start();
	}
}

7.2.2、方式二

class MyRunnable implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
}

public class Main {
	public static void main(String[] args) {
		MyRunnable my = new MyRunnable();
		Thread t1 = new Thread(my, "執行緒一");
		Thread t2 = new Thread(my, "執行緒二");
		t1.start();
		t2.start();
	}
}

7.3、執行緒優先順序

class ThreadPriority extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}

public class Main {
	public static void main(String[] args) {
		ThreadPriority tp1 = new ThreadPriority();
		ThreadPriority tp2 = new ThreadPriority();
		ThreadPriority tp3 = new ThreadPriority();
		// 設定執行緒的名稱
		tp1.setName("高鐵");
		tp2.setName("飛機");
		tp3.setName("汽車");
		// 返回執行緒優先順序
		System.out.println(tp1.getPriority());
		System.out.println(tp2.getPriority());
		System.out.println(tp3.getPriority());
		// 設定執行緒優先順序
		tp1.setPriority(5);
		tp2.setPriority(10);
		tp3.setPriority(1);
		// 啟動所有的執行緒
		tp1.start();
		tp2.start();
		tp3.start();
	}
}

7.4、執行緒的控制

sleep演示:使當前正在執行的執行緒停留(暫停執行)指定的毫秒數

class ThreadSleep extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName() + ":" + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class Main {
	public static void main(String[] args) {
		ThreadSleep ts1 = new ThreadSleep();
		ThreadSleep ts2 = new ThreadSleep();
		ThreadSleep ts3 = new ThreadSleep();
		ts1.setName("曹操");
		ts2.setName("劉備");
		ts3.setName("孫權");
		ts1.start();
		ts2.start();
		ts3.start();
	}
}

join演示:等待這個執行緒死亡才能執行其它執行緒

class ThreadJoin extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}

public class Main {
	public static void main(String[] args) {
		ThreadJoin tj1 = new ThreadJoin();
		ThreadJoin tj2 = new ThreadJoin();
		ThreadJoin tj3 = new ThreadJoin();
		tj1.setName("曹操");
		tj2.setName("劉備");
		tj3.setName("孫權");
		tj1.start();
		try {
			tj1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		tj2.start();
		tj3.start();
	}
}

Daemon演示:將此執行緒標記為守護執行緒,當執行的執行緒都是守護執行緒時,Java虛擬機器將退出

class ThreadDaemon extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}

public class Main {
	public static void main(String[] args) {
		ThreadDaemon td1 = new ThreadDaemon();
		ThreadDaemon td2 = new ThreadDaemon();
		td1.setName("關羽");
		td2.setName("張飛");
		// 設定主執行緒為劉備
		Thread.currentThread().setName("劉備");
		// 設定守護執行緒
		td1.setDaemon(true);
		td2.setDaemon(true);
		// 啟動守護執行緒
		td1.start();
		td2.start();
		// 執行主執行緒的邏輯
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
}

7.5、執行緒的生命週期

7.6、解決多執行緒資料安全問題

7.6.1、同步程式碼塊

class SellTicket implements Runnable {
	private int tickets = 100;
	private Object obj = new Object();

	@Override
	public void run() {
		while (true) {
			synchronized (obj) {
				if (tickets > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
					tickets--;
				}
			}
		}
	}
}

public class Main {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st, "視窗1");
		Thread t2 = new Thread(st, "視窗2");
		Thread t3 = new Thread(st, "視窗3");
		t1.start();
		t2.start();
		t3.start();
	}
}

7.6.2、普通同步方法

class SellTicket implements Runnable {
	private int tickets = 100;

	@Override
	public void run() {
		while (true) {
			sellTicket();
		}
	}

	private synchronized void sellTicket() {
		if (tickets > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
			tickets--;
		}
	}
}

public class Main {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st, "視窗1");
		Thread t2 = new Thread(st, "視窗2");
		Thread t3 = new Thread(st, "視窗3");
		t1.start();
		t2.start();
		t3.start();
	}
}

7.6.3、靜態同步方法

class SellTicket implements Runnable {
	private static int tickets = 100;

	@Override
	public void run() {
		while (true) {
			sellTicket();
		}
	}

	private static synchronized void sellTicket() {
		if (tickets > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
			tickets--;
		}
	}
}

public class Main {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st, "視窗1");
		Thread t2 = new Thread(st, "視窗2");
		Thread t3 = new Thread(st, "視窗3");
		t1.start();
		t2.start();
		t3.start();
	}
}

7.6.4、Look鎖

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class SellTicket implements Runnable {
	private int tickets = 100;
	private Lock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
			try {
				// 獲得鎖
				lock.lock();
				if (tickets > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
					tickets--;
				}
			} finally {
				// 釋放鎖
				lock.unlock();
			}
		}
	}
}

public class Main {
	public static void main(String[] args) {
		SellTicket st = new SellTicket();
		Thread t1 = new Thread(st, "視窗1");
		Thread t2 = new Thread(st, "視窗2");
		Thread t3 = new Thread(st, "視窗3");
		t1.start();
		t2.start();
		t3.start();
	}
}

7.7、生產者和消費者模式

概述:生產者消費者模式是一個十分經典的多執行緒協作的模式,弄懂生產者消費者問題能夠讓我們對多執行緒程式設計的理解更加深刻。

演示:

class Box {
	// 定義一個成員變數,表示第幾瓶牛奶
	private int milk;
	// 定義一個成員變數,表示奶箱的狀態
	private boolean state = false;

	// 儲存牛奶
	public synchronized void put(int milk) {
		// 如果有牛奶,等待消費
		if (state) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 如果沒有牛奶,就生產牛奶
		this.milk = milk;
		System.out.println("送奶工送第" + this.milk + "瓶奶");
		// 生產完畢之後,修改奶箱狀態
		state = true;
		// 喚醒其它等待的執行緒
		notifyAll();
	}

	// 獲取牛奶
	public synchronized void get() {
		// 如果沒有牛奶,等待生產
		if (!state) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		// 如果有牛奶,就消費牛奶
		System.out.println("使用者拿到第" + this.milk + "瓶奶");
		// 消費完畢之後,修改奶箱狀態
		state = false;
		// 喚醒其它等待的執行緒
		notifyAll();
	}
}

// 生產者
class Producer implements Runnable {
	private Box b;

	public Producer(Box b) {
		this.b = b;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			b.put(i);
		}
	}
}

// 消費者
class Customer implements Runnable {
	private Box b;

	public Customer(Box b) {
		this.b = b;
	}

	@Override
	public void run() {
		while (true) {
			b.get();
		}
	}
}

public class Main {
	public static void main(String[] args) {
		Box b = new Box();
		Producer p = new Producer(b);
		Customer c = new Customer(b);
		Thread t1 = new Thread(p);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}
}