【JavaSE:1.多執行緒】
- 最初場景:生產者消費者模式
模擬買票Ticket
package multiThread;
public class Ticket implements Runnable {
//共100票
int ticket = 100;
@Override
public void run() {
//模擬賣票
while (true) {
if (ticket > 0) {
//模擬選坐的操作
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在賣票:" + ticket--);
}
}
}
}
測試類ThreadDemo
package multiThread;
public class ThreadDemo {
public static void main(String[] args) {
//建立票物件
Ticket ticket = new Ticket();
//建立3個視窗s
Thread t1 = new Thread(ticket, "視窗1");
Thread t2 = new Thread(ticket, "視窗2");
Thread t3 = new Thread(ticket, "視窗3");
t1.start();
t2.start();
t3.start();
}
}
===進階版本
package multiThread;
import java.util.LinkedList;
import java.util.Queue;
/**
*
* @author ziboris
* @date 2018年11月23日 上午9:15:43
*
*/
//1.queue的所有操作都會notifyAll 但是目前一定有一個執行緒觸發這個notifyall
//其他執行緒因為還需要甦醒之後排程時間,肯定競爭不過他
//因此基本{產生滿,同一個消費者消費完畢},{},{}....
//---》解決方案 在A出加上sleep程式碼塊
public class ProducerConsumer {
public static class Producer extends Thread {// 生產者阻塞時候是判滿
Queue<Integer> queue;
int maxSize;
public Producer(Queue<Integer> queue, int maxSize, String name) {
this.queue = queue;
this.maxSize = maxSize;
this.setName(name);
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
// LinkedBlockingQueue<Integer> bQueue=new LinkedBlockingQueue<>();
while (true) {
// A
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: handle exception
}
synchronized (queue) {
System.out.println(this.getName() + " is in lock");
if (queue.size() == maxSize) {
System.out.println("queue is full--" + this.getName() + "--so waiting");
try {
queue.wait();// wait在queue這個資源上面 儲存一份阻塞時候的狀態,到時候被喚醒的時候可以直接往下面執行
} catch (Exception e) {
// TODO: handle exception
}
}
int num = (int) (Math.random() * 100);
queue.offer(num);// offer在加滿的時候會返回一個false put會一直等待知道出現空位 add會丟擲異常
System.out.println(this.getName() + "-produce a ticket:-" + num);// 執行緒的子類可以用getname獲取到初始化的name或者setname
queue.notifyAll();// 因為其他被阻塞的執行緒都等待在queue這個資源上面
System.out.println(" log out a produce");
}
}
}
}
public static class Consumer extends Thread {
Queue<Integer> queue;
int maxSize;
public Consumer(Queue<Integer> queue, int maxSize, String name) {
// TODO Auto-generated constructor stub
this.queue = queue;
this.maxSize = maxSize;
this.setName(name);
}
@Override
public void run() {
// TODO Auto-generated method stub
// super.run();
while (true) {
try {
Thread.sleep(200L);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (queue) {
System.out.println(this.getName() + " is in lock");
if (queue.isEmpty()) {
System.out.println("queue is empty--" + this.getName() + "--so waiting");
try {
queue.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
int num = queue.poll();// queue的remove和poll都是去除第一個元素,空的時候一個是返回exception,null
System.out.println(this.getName() + "- consume a ticket-" + num);
queue.notifyAll();
System.out.println(this.getName() + " log out a consume");
}
}
}
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
int maxSize = 10;
Producer producer = new Producer(queue, maxSize, "Producer");
Consumer consumer1 = new Consumer(queue, maxSize, "consumer1");
Consumer consumer2 = new Consumer(queue, maxSize, "consumer2");
Consumer consumer3 = new Consumer(queue, maxSize, "consumer3");
producer.start();
consumer1.start();
consumer2.start();
consumer3.start();
}
}
- 併發和並行
並行 | 多個cpu例項或者多臺機器同時執行一段處理邏輯,是真正的同時 |
---|---|
併發 | 通過cpu排程演算法,讓使用者看上去同時執行,實際上從cpu操作層面不是真正的同時。 |
-
執行緒狀態與狀態轉換
-
join
下面程式如果不join:
—Main Thread is finished
Thread2 begins:Thu Nov 22 20:17:39 CST 2018
Thread1 begins:Thu Nov 22 20:17:39 CST 2018
Thread1 has finished: Thu Nov 22 20:17:44 CST 2018
Thread2 has finished: Thu Nov 22 20:17:44 CST 2018
發現main結束的時候兩個子執行緒還沒有啟動好
加上join(1,2先後隨機)
Thread2 begins:Thu Nov 22 20:20:02 CST 2018
Thread1 begins:Thu Nov 22 20:20:02 CST 2018
Thread2 has finished: Thu Nov 22 20:20:07 CST 2018
Thread1 has finished: Thu Nov 22 20:20:07 CST 2018
—Main Thread is finished
package multiThread;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class TestJoin implements Runnable {
private String name;
public TestJoin(String name) {
this.name = name;
}
public void run() {
System.out.printf("%s begins:%s\n", name, new Date());
try {
TimeUnit.SECONDS.sleep(5L);
} catch (InterruptedException e) {
e.printStackTrace();
// TODO: handle exception
}
System.out.printf("%s has finished: %s\n", name, new Date());
}
public static void main(String[] args) {
Thread thread1 = new Thread(new TestJoin("Thread1"));
Thread thread2 = new Thread(new TestJoin("Thread2"));
thread1.start();
thread2.start();
// try {
// thread1.join();
// thread2.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// // TODO: handle exception
// }
System.out.println("---Main Thread is finished");
}
}
- wait notify && notifyall
Causes the current thread to wait until another thread invokes
沉睡自己,知道其他執行緒喚醒自己 notify notifyall執行緒在執行的時候,如果發現某些條件沒有被滿足,可以呼叫wait方法暫停自己的執行,並且放棄已經獲得的鎖,然後進入等待狀態。當該執行緒被其他執行緒喚醒並獲得鎖後,可以沿著之前暫停的地方繼續向後執行,而不是再次從同步程式碼塊開始的地方開始執行。但是需要注意的一點是,對執行緒等待的條件的判斷要使用while而不是if來進行判斷。這樣線上程被喚醒後,會再次判斷條件是否正真滿足。
- 基本執行緒類 Thread類,Runnable介面,Callable介面
extends Thread還是implement runnable (二者基本類似 ,區別見下)
參考博文:java建立執行緒implement runnable 和 extends thread 比較
Thread(runnable):
//當前執行緒可轉讓cpu控制權,讓別的就緒狀態執行緒執行(切換)
public static Thread.yield()
//yield()的作用是讓步。它能讓當前執行緒由“執行狀態”進入到“就緒狀態”,大家再次同一起跑線競爭
//暫停一段時間
public static Thread.sleep()
//在一個執行緒中呼叫other.join(),將等待other執行完後才繼續本執行緒。
public join()
//後兩個函式皆可以被打斷
public interrupte()
- synchronized wait notify notifyAll 是任何物件都具有的方法,因為任何物件都是一個資源
java中每一個物件都有一個monitor監視器,只在多執行緒的時候發揮作用
synchronized wait notify 必須是針對同一個物件資源
每一個物件的monitor有一個進入佇列和等待佇列(實質上多等待著佔有這個資源)
- volatile 多執行緒之間實時看見這個變數
執行緒的建立的時候是將main執行緒記憶體load到自己的執行緒棧裡面,完成run之後再save回去
volatile的作用是每一次的改變操作都會立馬save回去 因此main中需要交給各個執行緒處理的變數要麼是volatile 要麼是final
- 高階多線層控制工具類:java.util.concurrent包裡面since jdk1.5
ThreadLocal 為變數在每個執行緒中都建立了一個副本,那麼每個執行緒可以訪問自己內部的副本變數(如session)(牆裂推薦這個連結)
Atomic***(AtomicInteger AtomicBoolean)
Lock
容器類
管理類
【補充】
- 執行緒優先順序:
Java執行緒可以有優先順序的設定,高優先順序的執行緒比低優先順序的執行緒有更高的機率得到執行
優先順序可以用從1到10的範圍指定。10表示最高優先順序,1表示最低優先順序,5是普通優先順序(default)
- 設定執行緒名字和執行緒組名字
看執行緒出問題 jstack -pid 使用trycatch不行
執行緒組,批量管理多個執行緒
- Thread.currentThread()與this的區別
參考資料:Thread.currentThread()與this的區別
this 在類裡面如論如何都指向這個類
但是在這個自定義執行緒類中,只有run裡面this和currentThread才相等