這一則博客主要寫的是單例設計模式,與實現多線程之間的通信等等~
1.單例設計模式:保證類在內存中只有一個對象
2.保證類在內存中只有一個對象
(1)控制類的創建,不讓其他類來創建本類的對象。用private私有構建函數
(2)在本類中定義一個本類的對象。
(3)提供公共的訪問形式
3.單例寫法
(1)餓漢式
(2)懶漢式
(3)直接用final修飾 (private static final Single3 s=new Single3();)
餓漢式與懶漢式的區別:
(1)餓漢式是空間換時間,懶漢式是時間換空間
(2)在多線程訪問時,餓漢式不會創建多個對象,懶漢式有可能會創建多個對象
4.Runtime類:使用了單例設計模式,是一個單例類
5.Timer類(計時器):一種工具,線程用其安排以後在後臺線程中執行的任務。可安排任務執行一次,或者定期重複執行
schedule(TimeTask task,Date time),安排在指定的時間執行指定的任務
t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000); 安排指定任務在指定時間開始進行重複的固定延遲執行
第一個參數是安排的任務,第二個參數是執行時間,第三個參數是過多長時間再重複執行
6.兩個線程間的通信
什麼時候需要通信?
在多個線程併發執行時,在默認情況下cpu是隨機切換線程的;如果我們希望它們有規律的執行,就可以使用通信,例如每一次線程執行一次打印
如何進行通信?
如果希望線程等待,就調用wait();如果希望喚醒等待的線程,就調用notify();這兩個方法必須再同步代碼中執行,並且使用同步鎖對象來調用
wait(),notify()和notifyAll()方法
7.三個或三個以上間的線程通信
(1)notify()方法是隨機喚醒一個線程
(2)notifyAll()方法是喚醒所有線程
如果多個線程之間通信,需要使用notifyAll()通知所有線程,用while來反覆判斷條件
8.線程之間通信需要注意的問題
(1)在同步代碼塊中,用哪個對象鎖就用哪個對象調用wait()方法
(2)因爲鎖對象可以是任意對象,且Object類是所有類的基類所有將wait()和notify()方法定義在Object類中
(3)sleep方法和wait方法的區別
1)sleep方法必須傳入參數,參數是時間,時間道理自動醒來;wait方法可以傳入參數,在參數的時間結束後等待, 不傳入參數就是直接等待
2)sleep方法在同步函數或同步代碼塊中不釋放鎖;wait方法在同步函數或者同步代碼塊中,釋放鎖
9.互斥鎖
(1)同步:使用ReentrantLock類的lock()和unlock()方法進行同步
(2)通信
1)使用ReentrantLock類的newCondition()方法可以獲取Condition對象(使用await與signal方法)
2)需要等待的時候使用Condition的await()方法,喚醒的時候使用signal()方法
3)不同的線程使用不同的Condition,這樣就能區分喚醒的時候找哪個線程
在運行下面測試代碼中,可以一個案例一個案例運行,因爲會有可能會出一些問題,比如說前面的死循環無法運行下一個例子要實現的函數等等....
package pra_21;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class J_40 {
/**
* @param args
* @throws IOException
* @throws InterruptedException
*/
public static void main(String[] args) throws IOException, InterruptedException {
/*
//1.單例設計模式
//Single s1=new Single();
//Single s2=Single.s; //成員變量被私有,不能通過類名點去調用,解決了調用改變類的成員變量s
Single s3=Single.getS();
Single s4=Single.getS(); //此時不能修改
System.out.println(s3==s4);
//2.Runtime類
Runtime rt=Runtime.getRuntime(); //獲取運行是對象
//在單獨的進程中執行指定的字符串命令
//rt.exec("shutdown -s -t 300");
//rt.exec("shutdown -a");
//3.Timer類
Timer t=new Timer(); //創建計時器
t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50));//安排指定時間執行指定任務
//第一個參數是安排的任務,第二個參數是執行時間,第三個參數是過多長時間再重複執行
//t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000);//安排指定任務在指定時間開始進行重複的固定延遲執行
while(true){
Thread.sleep(1000);
System.out.println(new Date());
}
*/
//4.兩個線程之間的通信
//等待喚醒機制
final Pr2 p2=new Pr2();
new Thread(){
public void run(){
while(true){
try {
p2.pri();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
try {
p2.pri2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
//5.多個線程之間的通信
final Pr3 p3=new Pr3();
new Thread(){
public void run(){
while(true){
try {
p3.pri();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
try {
p3.pri2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
try {
p3.pri3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
//9.互斥鎖
final Pr3 pr4=new Pr3();
new Thread(){
public void run(){
while(true){
try {
pr4.pri();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
try {
pr4.pri2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread(){
public void run(){
while(true){
try {
pr4.pri3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
//餓漢式寫法,看法常用
class Single{
//1.私有構造方法,其他類不能訪問該構造方法
private Single(){}
//2.創建本類對象
private static Single s=new Single(); //如果是非靜態的成員變量就只能用對象名點去調用,加了靜態以後可以用類名點,但是被私有就不行
//3.對外提供公告的訪問方法(get set方法),主要是不讓其改變s的值
public static Single getS(){ //獲取對象(實例)
return s;
}
}
//懶漢式,單例的延遲加載模式,會出現多線程不安全的問題
class Single2{
//1.私有構造方法,其他類不能訪問該構造方法
private Single2(){}
//2.聲明引用
private static Single2 s; //
//3.對外提供公告的訪問方法(get set方法)
public static Single2 getS(){ //獲取對象(實例)
if(s==null){
s=new Single2();
}
return s;
}
}
//第三種
class Single3{
//1.私有構造方法,其他類不能訪問該構造方法
private Single3(){}
//2.聲明引用
private static final Single3 s=new Single3(); //直接用final修飾,使其不能不改變
}
//Timer
class MyTimerTask extends TimerTask{
@Override
public void run() {
System.out.println("走你!");
}
}
//等待喚醒機制:兩個方法 wait(),notify()方法,notifyAll()方法
class Pr2{
private int flag=1;
public void pri() throws InterruptedException{
synchronized(this){
if(flag!=1){
this.wait(); //當前線程等待
}
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.print("1");
System.out.println();
flag=2;
this.notify(); //隨機喚醒單個等待線程
}
}
public void pri2() throws InterruptedException{
synchronized(this){
if(flag!=2){
this.wait();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.print("2");
System.out.println();
flag=1;
this.notify();
}
}
}
//多個線程
class Pr3{
private int flag=1;
public void pri() throws InterruptedException{
synchronized(this){
while(flag!=1){
this.wait(); //當前線程等待
}
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.print("1");
System.out.println();
flag=2;
this.notifyAll(); //隨機喚醒單個等待線程
}
}
public void pri2() throws InterruptedException{
synchronized(this){
while(flag!=2){
this.wait();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.print("2");
System.out.println();
flag=3;
this.notifyAll();
}
}
public void pri3() throws InterruptedException{
synchronized(this){
while(flag!=3){
this.wait(); //線程3再此等待,if語句是在哪裏等待,就在哪裏起來,while則可以
//while循環是循環判斷,每一次都會判斷標記
}
System.out.print("u");
System.out.print("i");
System.out.print("o");
System.out.print("p");
System.out.print("3");
System.out.println();
flag=1;
this.notifyAll();
}
}
}
//使用互斥鎖實現多線程
class Pr4{
private ReentrantLock r=new ReentrantLock();
private Condition c1=r.newCondition();
private Condition c2=r.newCondition();
private Condition c3=r.newCondition();
private int flag=1;
public void pri() throws InterruptedException{
r.lock(); //獲取鎖
if(flag!=1){
c1.await(); //當前線程等待
}
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.print("1");
System.out.println();
flag=2;
c2.signal();
r.unlock(); //釋放鎖
}
public void pri2() throws InterruptedException{
r.lock();
if(flag!=2){
c2.await();
}
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.print("2");
System.out.println();
flag=3;
c3.signal();
r.unlock();
}
public void pri3() throws InterruptedException{
r.lock();
if(flag!=3){
c3.await();
}
System.out.print("u");
System.out.print("i");
System.out.print("o");
System.out.print("p");
System.out.print("3");
System.out.println();
flag=1;
c1.signal();
r.unlock();
}
}