多線程簡單入門之如何實現通訊?
一.什麼是多線程之間通訊?
多個線程操作同一資源,操作的動作不同。例如某個對某個對象的讀和寫,相當於兩個線程操作該對象作不同的動作。
該需求代碼如下:
/**
* 多線程之間通訊
* 2019/11/27
*/
class PeopleTest {
public String name;
public String sex;
}
class InputPeople extends Thread {
private PeopleTest people;
// 構造函數
public InputPeople(PeopleTest people) {
this.people = people;
}
@Override
public void run() {
int num = 0;
while (true) {
if (num == 0) {
people.name = "莫吊";
people.sex = "男";
} else {
people.name = "翠花";
people.sex = "女";
}
num = (num + 1) % 2;
}
}
}
class OutPeople extends Thread {
private PeopleTest people; // 共享資源實體類對象
// 構造函數
public OutPeople(PeopleTest people) {
this.people = people;
}
@Override
public void run() {
while (true) {
System.out.println(people.name + "性別--" + people.sex);
}
}
}
public class ThreadTest1 extends Thread {
public static void main(String[] args) {
PeopleTest people = new PeopleTest();
InputPeople inputPeople = new InputPeople(people);
OutPeople outPeople = new OutPeople(people);
inputPeople.start();
outPeople.start();
}
}
運行部門結果如下:
如圖運行結果會出現此情況,是因爲讀和寫兩個線程共享同一資源導致的線程不安全現象。
二.wait()、notify()、notifyAll()方法
wait()方法和sleep()方法類似,但是wait會釋放鎖和synchronize與notify一起使用。
他們都在Object類中,對象鎖也就是類鎖,他們都是Object的子類,所以方便所以類都能使用該方法。
代碼如下:
/**
* 多線程之間通訊
* 2019/11/27
*/
class PeopleTest {
public String name;
public String sex;
public boolean aa=false;
}
class InputPeople extends Thread {
private PeopleTest people;
// 構造函數
public InputPeople(PeopleTest people) {
this.people = people;
}
@Override
public void run() {
int num = 0;
while (true) {
synchronized (people) {
if (people.aa) {
try {
// 當前線程等待 可以釋放鎖
people.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
if (num == 0) {
people.name = "莫吊";
people.sex = "男";
} else {
people.name = "翠花";
people.sex = "女";
}
num = (num + 1) % 2;
people.aa = true;
people.notify(); // 喚醒線程
}
}
}
}
class OutPeople extends Thread {
private PeopleTest people; // 共享資源實體類對象
// 構造函數
public OutPeople(PeopleTest people) {
this.people = people;
}
@Override
public void run() {
while (true) {
synchronized (people) {
if (!people.aa) {
try {
people.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(people.name + "性別--" + people.sex);
people.aa = false;
people.notify();
}
}
}
}
public class ThreadTest1 extends Thread {
public static void main(String[] args) {
PeopleTest people = new PeopleTest();
InputPeople inputPeople = new InputPeople(people);
OutPeople outPeople = new OutPeople(people);
inputPeople.start();
outPeople.start();
}
}
運行部門如下:
這樣實現了邊寫邊讀的情況,這樣線程不會出現操作錯誤。
三.JDK1.5 lock鎖。
JDK1.5提供了併發包,lock鎖、線程池Executor。lock獲取鎖資源,unlock釋放鎖。與synchronize類似的同步功能,但不同於synchronize自動獲取鎖、釋放鎖,lock需要手動獲取和釋放鎖。
部分代碼如下:
定義在實體類中是因爲後面需要用到同一把lock鎖。
運行結果如下:
現在需要解決的是線程安全問題。
使用condition的await和signal方法獲取和釋放鎖。
部分代碼如下:
實現效果如下:
達到了邊寫邊讀的要求, 這樣就解決了線程安全問題。
三.怎麼停止線程?
使用stop方法強行終止線程,但不推薦使用,因爲根據現在的api提示可能會發生不可預料的結果。我們可以使用退出標誌,讓線程正常退出,當run方法完成後終止。
代碼如下:
class StopThread2 extends Thread{
/**
* 多線程通訊 停止線程
* 2019/11/27
*/
public boolean aa=true;
@Override
public void run(){
while(aa) {
System.out.println(Thread.currentThread().getName()+"----這是一個子線程");
}
}
public void Stop(){
aa=false;
System.out.println(getName()+"線程停止了。");
}
}
public class StopThread{
public static void main(String[] args) {
StopThread2 stopThread1 = new StopThread2();
StopThread2 stopThread2 = new StopThread2();
stopThread1.start();
stopThread2.start();
for (int i=0;i<30;i++) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("這是一個主線程..");
if (i == 29) {
stopThread1.Stop();
stopThread2.Stop();
}
}
}
}
運行結果如下:
注:這裏是因爲線程被停止了,還是還在執行,但是這樣還是不合理,應中斷線程。
四.怎樣中斷線程?
代碼如下:
class StopThread2 extends Thread{
/**
* 多線程通訊 停止線程
* 2019/11/27
*/
public boolean aa=true;
@Override
public synchronized void run(){
while(aa) {
try{
wait();
}catch (Exception e){
Stop();
}
System.out.println(Thread.currentThread().getName()+"----這是一個子線程");
}
}
public void Stop(){
aa=false;
System.out.println(getName()+"線程停止了。");
}
}
public class StopThread{
public static void main(String[] args) {
StopThread2 stopThread1 = new StopThread2();
StopThread2 stopThread2 = new StopThread2();
stopThread1.start();
stopThread2.start();
for (int i=0;i<30;i++) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("這是一個主線程..");
if (i == 29) {
stopThread1.interrupt();
stopThread2.interrupt();
}
}
}
}
注:這裏我沒有拋異常,調用的stop方法。
運行結果:
線程被中斷了。
五.怎樣守護線程?
java中有兩種線程:一種守護線程(主線程);一種用戶線程。
當進程不存在或主線程停止,守護線程也會被停止。 使用setDaemon(true)方法設置爲守護線程。
注:該博客純個人學習筆記,歡迎交流。