線程一些小知識的整理。
需求: 使用線程同步和通信,解決生產者和消費者的問題!
技能:
1.線程同步---推薦使用同步代碼塊(同步鎖---建議使用共享資源)
2.實現多線程----推薦使用實現Runnable接口
3.通信的方法---三個方法
說明: 他們都存在Object類當中,因爲Object類是任何的類的父類,子類都可以通過繼承關係,繼承三個通信的方法!
根據三個方法的定義,他們都使用了final修飾,也就是說,子類只能繼承不能重寫!
線程等待---wait()方法
特點:1.在線程等待的同時,釋放同步鎖!
2.只能等待另外一個線程的通知/喚醒,此線程才能繼續運行!
筆試題: wait()方法和sleep()方法的異同! --- 作業題。
線程的喚醒----notify()方法
特點: 只能喚醒等待的線程,不能喚醒休眠的線程!
喚醒所有的線程---notifyAll()方法
特點: 喚醒所有正在等待的線程
對於正在等待的線程,那個線程優先級別高,就先喚醒誰!(謹記: 即使全部喚醒,同時線程的優先級高的線程,也不一定先執行!)
代碼區:(重中之重)
public class Consumer implements Runnable {
//屬性---成員變量
private Product pro;
//get set方法
public Product getPro() {
return pro;
}
public void setPro(Product pro){
this.pro = pro;
}
//構造方法
public Consumer() {
super();
}
public Consumer(Product pro) {
super();
this.pro = pro;
}
//重寫run()方法
public void run() {
//消費產品
while(true){
//通過產品類對象,調用消費方法
pro.get();
}
}
}
public class Producer implements Runnable{
//定義屬性---成員變量
private Product pro = null;
//get set方法
public Product getPro() {
return pro;
}
public void setPro(Product pro) {
this.pro = pro;
}
//構造方法
public Producer() {
super();
// TODO Auto-generated constructor stub
}
//目的: 爲了防止出現空指針異常
public Producer(Product pro) {
super();
this.pro = pro;
}
//重寫run方法
public void run() {
//定義一個變量 i 初始化值爲0 目的: 爲了區分生產饅頭還是玉米餅 如果i%2==0 生產饅頭,反之,生產玉米餅
int i =0;
//循環的進行生產,以便能生產饅頭和玉米餅,如果不使用循環語句,則只會生產一次,而且只是饅頭
while(true){
if(i%2==0){
pro.put("饅頭", "白色");
}else{
pro.put("玉米餅", "黃色");
}
//改變if語句當中的布爾值,如果爲true,則生產饅頭,反之,生產玉米餅
i++;
}
}
}
/**
* Product類: 產品類
* 目的:1.使用此類對象,充當同步鎖(同步監視器)
* 2.把產品的屬性以及get set方法和構造方法,寫入到此類,供以後使用
* 同時,把生產的方法和消費的方法,也寫入到此類中!
* 原因: 在使用同步的時候,會調用這個兩個方法!
*
* 生產饅頭和玉米餅
* 饅頭---白色
* 玉米餅---黃色
*/
public class Product {
//屬性
private String name;
private String color;
//定義一個boolean類型的變量,目的: 爲了在生產以及消費當中,進行判斷而用
private boolean isProduct = false;
//get set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//構造方法
public Product() {
super();
}
public Product(String name, String color) {
super();
this.name = name;
this.color = color;
}
//toString()方法
@Override
public String toString() {
return "Product [name=" + name + ", color=" + color + "]";
}
//生產和消費的方法---要求這兩個方法使用同步方法!
// 生產的方法,此方法的形參: 產品的名稱和產品的顏色
public synchronized void put(String name,String color){
//1.1 先進性判斷,消費者判斷倉庫當中是否有產品
if(isProduct){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//1.2 生產產品
this.name=name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.color=color;
System.out.println(Thread.currentThread().getName()+"生產:"+name+" "+color);
//1.3 修改boolean類型的變量,目的: 說明倉庫已經有產品了,不用再生產了
isProduct = true;
//1.4 喚醒消費者線程
notify();
}
//消費的方法
public synchronized void get(){
//1.1 判斷
if(!isProduct){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//1.2 消費產品
System.out.println(Thread.currentThread().getName()+"消費產品:"+this.getName()+"---"+this.getColor());
//1.3 修改boolean變量的值
isProduct = false;
//1.4 喚醒生產者線程,進行生產
notify();
}
}
public class Test {
public static void main(String[] args) {
//1.創建產品類對象,目的: 爲生產者線程和消費線程的構造方法做準備
Product pro = new Product();
//2.創建Runnalbe接口對象
Runnable r1 = new Producer(pro);
Runnable r2 = new Consumer(pro);
//3.藉助Thread類,創建線程,並啓動線程
Thread t1 = new Thread(r1,"生產者------");
Thread t2 = new Thread(r2,"消費者---");
t1.start();
t2.start();
}
}
原博地址(也是我,O(∩_∩)O哈哈~):http://m15231417197.lofter.com/
練習代碼地址(嘿嘿嘿):https://download.csdn.net/download/m15231417197/10716486