JavaSE基礎學習筆記及案例(二)多執行緒(下)與簡單工廠模式的瞭解
1.多執行緒(下)
1.1單例設計模式:保證類在記憶體中只存在一個物件
************餓漢式與懶漢式的區別【面試題】
- 餓漢式單例模式:以空間換時間
- 懶漢式單例模式:以時間換空間(不推薦使用,僅在面試中用到)
3.多執行緒訪問時:餓漢式不會建立多個物件;而懶漢式模式有可能會建立多個物件【弊端】
/* @author ZHENG * 餓漢式 */ class Singleton{ //1.私有構造方法,其他類不能訪問該構造方法 private Singleton(){ } //2.建立本類物件(私有成員變數) private static Singleton s = new Singleton(); //3.對外提供公共的訪問方法 public static Singleton getInstance(){ return s; } }
/**
* @author ZHENG
* 懶漢式:單例延遲載入模式
*/
class Singleton{
//1.私有構造方法,其他類不能訪問該構造方法
private Singleton(){
}
//2.宣告一個引用
private static Singleton s;
//3.對外提供公共的訪問方法
public static Singleton getInstance(){
if(s==null){
//執行緒1等待,執行緒2等待
s=new Singleton();
}
return s;
}
}
1.2第三種單例設計模式
非重點
class Singleton{ //1.私有構造方法,其他類不能訪問該構造方法 private Singleton(){ } //2.宣告一個引用 public final static Singleton s=new Singleton(); }
1.3多執行緒之RunTime類(瞭解)
public class demo2_Runtime {
public static void main(String[] args) throws IOException{
Runtime r = Runtime.getRuntime();//獲取執行時物件
/*r.exec("shutdown -s -t 300");//設定電腦5分鐘後關機
*/ r.exec("shutdown -a");
}
}
1.4多執行緒之Timer類
Timer:一種計時器
TimerTask:建立一個計時器任務
t.schedule(安排的任務,new Date(當前年份-1900,月,日,時,分,秒),多長時間重複執行) //指定時間執行指定的任務
/**
* @author ZHENG
* timer指定時間安排指定任務
*/
public class demo3_Timer {
public static void main(String[] args) throws InterruptedException{
Timer t = new Timer();
//指定時間安排指定任務
//t.schedule(安排的任務,new Date(當前年份-1900,月,日,時,分,秒),多長時間重複執行)
//2018年11月3日
t.schedule(new MyTimerTask(), new Date(118,10,3,19,39,10), 3000);
while(true){
Thread.sleep(1000);
System.out.println(new Date());
}
}
}
class MyTimerTask extends TimerTask{
@Override
public void run() {
System.out.println("起床了...");
}
}
1.5多執行緒之執行緒之間的通訊
-------wait方法:其他物件呼叫此物件的notify,導致當前執行緒等待
-------notify:兩個執行緒間的通訊:喚醒等待的單個執行緒
-------notifyAll:多個執行緒間的通訊:喚醒所有執行緒
注意事項:1.在同步程式碼塊中,用哪個物件鎖,就用哪個物件呼叫wait方法;
2.sleep方法和wait方法區別?
—2.1.sleep必須傳入時間引數,時間到了自動醒來;
wait既可以傳入引數,也可以不傳入引數,如果傳入引數就是在引數時間結束後等待,若不傳入引數就是直接等待;
—2.2.sleep方法在同步函式或同步程式碼塊中,不釋放鎖;
wait方法在同步函式或者同步程式碼塊中釋放鎖;
以下程式碼為兩個執行緒之間的通訊
同步程式碼塊使用if判斷
public class demo4_notify {
/**
* @param args
*
* 等待喚醒機制
*/
public static void main(String[] args){
final Print p = new Print();
while(true){
new Thread(){
public void run(){
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
class Print{
private int flag = 1;
public void print1() throws InterruptedException{
//非靜態程式碼塊使用this
synchronized (this) {
if(flag != 1){
this.wait();//當前執行緒等待
}
System.out.print("好");
System.out.print("好");
System.out.print("學");
System.out.print("習");
System.out.println();
flag = 2;
this.notify();//隨機喚醒單個等待的執行緒
}
}
public void print2() throws InterruptedException{
//非靜態程式碼塊使用this
synchronized (this) {
if(flag != 2){
this.wait();//當前執行緒等待
}
System.out.print("天");
System.out.print("天");
System.out.print("向");
System.out.print("上");
System.out.println();
flag = 1;
this.notify();//隨機喚醒單個等待的執行緒
}
}
}
以下程式碼為多個執行緒間通訊,程式碼塊中使用while判斷
public class demo5_notifyAll {
/**
* @param args
* 三條執行緒呼叫三個方法:使用while
* 等待喚醒機制
*/
public static void main(String[] args){
final PrintAll p = new PrintAll();
while(true){
new Thread(){
public void run(){
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
p.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
class PrintAll{
private int flag = 1;
public void print1() throws InterruptedException{
//非靜態程式碼塊使用this
synchronized (this) {
while(flag != 1){
this.wait();//當前執行緒等待
}
System.out.print("好");
System.out.print("好");
System.out.print("學");
System.out.print("習");
System.out.println();
flag = 2;
this.notifyAll();//隨機喚醒所有等待的執行緒
}
}
public void print2() throws InterruptedException{
//非靜態程式碼塊使用this
synchronized (this) {
while(flag != 2){
this.wait();//當前執行緒等待
}
System.out.print("天");
System.out.print("天");
System.out.print("向");
System.out.print("上");
System.out.println();
flag = 3;
this.notifyAll();//隨機喚醒所有等待的執行緒
}
}
public void print3() throws InterruptedException{
//非靜態程式碼塊使用this
synchronized (this) {
while(flag != 3){
this.wait();//當前執行緒等待
}
System.out.print("-");
System.out.print("毛");
System.out.print("主");
System.out.print("席");
System.out.println();
flag = 1;
this.notifyAll();//隨機喚醒所有等待的執行緒
}
}
}
1.6多執行緒之互斥鎖
-----------ReentrantLock:建立互斥鎖>>>>>>>>>>ReentrantLock r = new ReentrantLock
----r.lock:獲取鎖
----r.unlock:釋放鎖
private ReentrantLock r = new ReentrantLock();//互斥鎖
private Condition c1 = r.newCondition();//建立3個監視器
private Condition c2 = r.newCondition();
private Condition c3 = r.newCondition();
對1.5由synchronized實現的多個執行緒間通訊優化(1.5特性)
public class demo1 {
public static void main(String[] args){
final PrintAll p = new PrintAll();
while(true){
new Thread(){
public void run(){
try {
p.print1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
p.print2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
new Thread(){
public void run(){
try {
p.print3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
class PrintAll{
private ReentrantLock r = new ReentrantLock();//互斥鎖
private Condition c1 = r.newCondition();//建立3個監視器
private Condition c2 = r.newCondition();
private Condition c3 = r.newCondition();
private int flag = 1;
public void print1() throws InterruptedException{
r.lock();//獲取鎖
if(flag != 1){
c1.await();//c1等待
}
System.out.print("好");
System.out.print("好");
System.out.print("學");
System.out.print("習");
System.out.println();
flag = 2;
c2.signal();//喚醒c2
r.unlock();//釋放鎖
}
public void print2() throws InterruptedException{
r.lock();
if(flag != 2){
c2.await();
}
System.out.print("天");
System.out.print("天");
System.out.print("向");
System.out.print("上");
System.out.println();
flag = 3;
c3.signal();
r.unlock();
}
public void print3() throws InterruptedException{
r.lock();
if(flag != 3){
c3.await();;
}
System.out.print("-");
System.out.print("毛");
System.out.print("主");
System.out.print("席");
System.out.println();
flag = 1;
c1.signal();
r.unlock();
}
}
1.7多執行緒的5種狀態【面試題】
1.8執行緒池
1.建立兩個執行緒池
ExecutorService pool = Executors.newFixedThreadPool(2);
2.工廠模式【瞭解】
2.1簡單工廠設計模式【瞭解】
第一步:建立一個抽象的Animal類
public abstract class Animal {
public abstract void eat();
}
第二步:建立貓和狗類物件繼承自Animal類
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("貓吃魚");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
第三步建立Animal的工廠類
public class Animal_Fac {
public static Animal creatAnimal(String name){
if("dog".equals(name)){
return new Dog();
}else if("cat".equals(name)){
return new Cat();
}else{
return null;
}
}
}
第四步:建立測試類實現簡單工廠模式
public class Test {
public static void main(String[] args){
Dog cd = (Dog) Animal_Fac.creatAnimal("dog");
cd.eat();
Animal ct = Animal_Fac.creatAnimal("cat");
ct.eat();
}
}
2.2工廠方法
第一步:建立動物抽象類,dog類與cat類分別繼承該抽象類,步驟如1.9前三步;
第二步:建立工廠介面
/**
* @author ZHENG
* 工廠介面
*/
public interface Fac_Inter {
public Animal creatAnimal();
}
第三步:分別建立Cat工廠和Dog工廠實現第二步中動物工廠介面
public class Cat_Fac implements Fac_Inter {
@Override
public Animal creatAnimal() {
return new Cat();
}
}
public class Dog_Fac implements Fac_Inter {
@Override
public Animal creatAnimal() {
return new Dog();
}
}
第四步:建立測試類,實現程式碼
public class Test {
public static void main(String[] args) {
Cat_Fac cf = new Cat_Fac();/*與建立狗工廠方法相同*/
Dog_Fac df = new Dog_Fac();//建立狗工廠物件
Dog d = (Dog) df.creatAnimal();//呼叫方法,向下強轉,得狗物件
d.eat();//狗物件呼叫方法
}
}
2.3介面卡設計模式
介面卡原理:
1.介面卡就是一個類實現監聽介面,所有抽象方法都被重寫,但是方法是空的;
2.介面卡需要定義成抽象的,因為建立該類物件,呼叫空方法無意義;
3.目的:簡化操作,定義監聽器時繼承介面卡,僅重寫需要的方法即可;
public class shipeiqi {
public static void main(String[] args){
}
}
interface 和尚{
public void 打坐();
public void 唸經();
public void 撞鐘();
public void 習武();
}
/**
* 該類即是介面卡類
*
* 宣告成抽象的,防止其他類呼叫水滸傳裡的方法,因為建立也無意義,方法都是空的
*/
abstract class 水滸傳 implements 和尚{
@Override
public void 打坐() {
}
@Override
public void 唸經() {
}
@Override
public void 撞鐘() {
}
@Override
public void 習武() {
}
}
/**
* 魯智深僅有習武這個方法
*
* 如果唐僧實現和尚這個介面,可以通過介面卡,需要哪個方法就重寫哪個方法
*/
class 魯智深 extends 水滸傳{
public void 習武(){
System.out.println("倒拔垂楊柳");
System.out.println("拳打鎮關西");
System.out.println("......");
}
}
2.4設計模式之模板(Template)
public class demo2 {
public static void main(String[] args){
Demo d = new Demo();
System.out.println(d.getTime());
}
}
/**
* @author
* 模板:定義一個框架模型,如需改動更改子類即可
*/
abstract class GetTime{
public final long getTime(){//子類不可更改該方法
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
return (end-start)/1000;
}
public abstract void code();//讓子類可以重寫該方法
}
class Demo extends GetTime{
@Override
public void code() {
for (int i = 0; i < 100000; i++) {
System.out.println(i);
}
}
}