【本節目标】
通過閱讀本節内容,你将通過實操代碼,進一步掌握synchronized關鍵字的使用方法,解決同步問題,學會使用Object類中提供的相關方法解決重複問題。
解決資料同步
如果要解決問題,首先解決的就是資料同步的處理問題,如果要想解決資料同步最簡單的做法就是使用synchronized關鍵字定義同步代碼塊或同步方法,于是這個時候對于同步的處理就可以直接在Message類中完成。
範例:解決同步操作
class Message {
private String title;
private String content;
public synchronized void set(String title, String content) {
this.title = title;
try {
Thread.sleep(100); //模拟網絡延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
}
public synchronized String get() {
try {
Thread.sleep(10); //模拟網絡延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.title + " - " + this.content;
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
Message msg = new Message();
new Thread(new Producer(msg)).start(); //啟動生産者線程
new Thread(new Consumer(msg)).start(); //啟動消費者線程
}
}
class Producer implements Runnable {
private Message msg;
public Producer(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (x % 2 == 0) {
this.msg.set("王健", "宇宙大帥哥");
} else {
this.msg.set("小高", "猥瑣第一人,常态保持");
}
}
}
}
class Consumer implements Runnable {
private Message msg;
public Consumer(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(this.msg.get());
}
}
}

圖一 執行結果圖
在進行同步處理的時候肯定需要有一個同步的處理對象,那麼此時肯定要将同步操作交由Message處理是最合适的。這時資料已經可以正常保持一緻了,但是對于重複操作的問題依然存在。
線程等待與喚醒
如果說現在要想解決生産者與消費者的問題,那麼最好的解決方案就是使用等待與喚醒機制。而對于等待與喚醒的操作機制主要依靠是Object類中提供的方法處理的:
等待機制:
1、死等:
public final void wait() throws InterruptedException;
2、設定等待時間(毫秒):
public final void wait(long timeout) throws InterruptedException;
3、設定等待時間(納秒):
public final void wait(long timeout, int nanos) throws InterruptedException;
喚醒第一個等待線程:public final void notify();
喚醒全部等待線程:public final void notifyAll();
如果此時有若幹個等待線程的話,那麼notify()表示的是喚醒第一個等待的,而其他的線程繼續等待,而notifyAll()表示會喚醒所有等待的線程,哪個線程的優先級高就有可能先執行。
對于目前的問題主要的解決應該通過Message類完成處理。
範例:修改Message類
public class ThreadDemo {
public static void main(String[] args) throws Exception {
Message msg = new Message();
new Thread(new Producer(msg)).start(); //啟動生産者線程
new Thread(new Consumer(msg)).start(); //啟動消費者線程
}
}
class Producer implements Runnable {
private Message msg;
public Producer(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (x % 2 == 0) {
this.msg.set("王健", "宇宙大帥哥");
} else {
this.msg.set("小高", "猥瑣第一人,常态保持");
}
}
}
}
class Consumer implements Runnable {
private Message msg;
public Consumer(Message msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(this.msg.get());
}
}
}
class Message {
private String title;
private String content;
private boolean flag = true; //表示生産或消費的形式
//flag = true:允許生産,但不允許消費
//flag = false:允許消費,但不允許生産
public synchronized void set(String title, String content) {
if(this.flag==false){ //無法進行生産,應該等待被消費
try {
super.wait();
}catch (Exception e){
e.printStackTrace();
}
}
this.title = title;
try {
Thread.sleep(100); //模拟網絡延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
this.flag=false; //已經生産過了
super.notify(); //喚醒等待的線程
}
public synchronized String get() {
if(this.flag==true){ //還未生産,需要等待
try {
super.wait();
}catch (Exception e){
e.printStackTrace();
}
}
try {
Thread.sleep(10); //模拟網絡延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
return this.title + " - " + this.content;
}finally { //不管如何都要執行
this.flag=true; //繼續生産
super.notify(); //喚醒等待的線程
}
}
}
圖二 線程的等待與喚醒
這種處理形式就是在進行多線程開發過程之中最原始的處理方案,整個的等待、同步、喚醒機制都由開發者自行通過原生代碼實作控制。
想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。
本内容視訊來源于
阿裡雲大學 下一篇:教你在停車前為線程配個“保镖” | 帶你學《Java語言進階特性》之十三 更多Java面向對象程式設計文章檢視此處