一、JUC系列之---線程基礎

1、多線程概述

一、進程:正在進行中的程序
二、線程:就是進程中一個負責程序執行的控制單元(執行路徑)java

一個進程中,能夠有多個執行路徑,即多線程小程序

一個進程中,至少有一個執行路徑。安全

(多線程其實就是多個線程中的快速切換)多線程

2、多線程的建立方式①--繼承Thread類

繼承Thread類,重寫run方法ide

一、JVM建立的主線程的任務都定義在了主函數中函數

二、Thread類中的run方法就是封裝自定義線程任務的函數,即run方法至關於一個main方法this

package com.lee.juc;

public class ThreadDemo_01 {

	public static void main(String[] args) {
		Demo demo1 = new Demo("張三");
		Demo demo2 = new Demo("LeeSi");
		
		demo1.start();
		demo2.start();
		System.out.println("=======結束========");
	}
	
}

class Demo extends Thread{
	private String name;

	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(name+"====>"+i);
		}
	}
	
	public Demo() {
		super();
	}
	public Demo(String name) {
		this.name = name;
	}
}

結果:spa

================================線程

注:調用Run和Start有什麼區別?code

 

================================

方法:

getName  獲取線程名稱

CurrentThread  返回當前正在執行線程的引用對象

3、多線程的建立方式②--實現Runnable接口

package com.lee.juc;

public class ThreadDemo_02 {

	public static void main(String[] args) {
		
		Demo2 d = new Demo2();
		
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		
		t1.start();
		t2.start();
		
	}
}

class Demo2 implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(i+"====>"+Thread.currentThread().getName());
		}
	}
}

結果:

===========================

注:經過implement Runnable接口的方法 

避免了單繼承 extends Thread的侷限性

===========================

 

4、線程狀態

再增長一個臨時阻塞狀態

5、賣票小程序

需求:四個窗口共同賣100張票

一、繼承Thread方法

NUM爲static

package com.lee.juc;

public class TicketDemo_01 {

	public static void main(String[] args) {
		
		Ticket_01 t1 = new Ticket_01();
		Ticket_01 t2 = new Ticket_01();
		Ticket_01 t3 = new Ticket_01();
		Ticket_01 t4 = new Ticket_01();
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_01 extends Thread{

	private static int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			if(NUM>0) {
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
			}else {
				break;
			}
		}
	}
	
}

結果:

二、實現Runnable接口

package com.lee.juc;

public class TicketDemo_02 {

	public static void main(String[] args) {
		Ticket_02 ticket = new Ticket_02();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_02 implements Runnable{

	private int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			if(NUM>0) {
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
			}else {
				break;
			}
		}
	}
	
}

結果:

6、線程安全問題現象

package com.lee.juc;

public class TicketDemo_03 {

	public static void main(String[] args) {
		Ticket_03 ticket = new Ticket_03();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_03 implements Runnable{

	private int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			
			if(NUM>0) {
				
                //======加sleep=======
				try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
				
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
				
			}else {
				break;
			}
		}
	}
	
}

結果:

產生緣由:

①、多個線程,操做同一個共享數據

②、操做共享數據的線程代碼有多條

7、同步代碼塊

就是將多條操做共享數據的線程代碼封裝起來,當有線程在執行這些代碼的時候,其餘線程不能夠參與運算。

必需要當前線程把這些代碼都執行完後,其餘線程才能執行。

同步代碼塊的格式:

synchronized(對象){

     須要被同步的代碼;

}

代碼:

package com.lee.juc;

public class TicketDemo_03 {

	public static void main(String[] args) {
		Ticket_03 ticket = new Ticket_03();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_03 implements Runnable{

	private int NUM = 100;

	Object obj = new Object();  	

	@Override
	public void run() {
		while(true) {
            //====================
			synchronized (obj) {
				if(NUM>0) {
					try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
					System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
				}else {
					break;
				}
			}
            //=====================
			
		}
	}
	
}

結果:

同步的好處和弊端:

好處:解決了線程安全的問題

弊端:相對下降了效率

注:

必須保證多個線程使用同一個鎖

8、同步函數

需求:

兩個儲戶去銀行存錢,每一個人存3次,每次存¥100

一、未加鎖的錯誤代碼

package com.lee.juc;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	public void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//兩人公用一個bank,因此bank提出來
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			bank.add(100);
		}
	}
	
}

二、加鎖,正確代碼

package com.lee.juc;

import org.omg.Messaging.SyncScopeHelper;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	public void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//兩人公用一個bank,因此bank提出來
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			//===========加鎖
			synchronized(bank) {
				bank.add(100);
			}
            //============
		}
	}
	
}

或者

package com.lee.juc;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	//同步函數鎖
	public synchronized void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//兩人公用一個bank,因此bank提出來
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			bank.add(100);
		}
	}
	
}

結果:

9、驗證同步函數的鎖

一、驗證是不是Object

package com.lee.juc;

public class TicketDemo_04 {

	public static void main(String[] args) {
		Ticket_04 ticket = new Ticket_04();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_04 implements Runnable{

	private int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (obj) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代碼塊....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函數.."+NUM--);
		}
	}
	
}

結果:

錯誤,證實不是obj

二、證實是否是this

package com.lee.juc;

public class TicketDemo_04 {

	public static void main(String[] args) {
		Ticket_04 ticket = new Ticket_04();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_04 implements Runnable{

	private int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代碼塊....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函數.."+NUM--);
		}
	}
	
}

結果:

證實是this

10、驗證靜態同步函數的鎖

代碼:

package com.lee.juc;

public class TicketDemo_05 {

	public static void main(String[] args) {
		Ticket_05 ticket = new Ticket_05();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_05 implements Runnable{

	private static int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this.getClass()) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代碼塊....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public static synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函數.."+NUM--);
		}
	}
	
}

結果:

注:

靜態同步函數的鎖是  當前文件的字節碼,this.getClass或TicketDemo_05.class

11、單例模式

//懶漢式
class SingleLazy{
	private static SingleLazy singleLazy;
	
	private SingleLazy() {}
	
	private static SingleLazy getInstance() {
		
		if(singleLazy==null) {
			synchronized (SingleLazy.class) {
				if(singleLazy==null) {
					singleLazy = new SingleLazy();
				}
			}
		}
		
		return singleLazy;
	}
	
}

//餓漢式--推薦使用這個
class SingleHungry{
	
	private static SingleHungry singleHungry = new SingleHungry();
	
	private SingleHungry() {}
	
	private static SingleHungry getInstance() {
		return singleHungry;
	}
	
}

12、死鎖的情景

產生情景:

一、同步的嵌套:A鎖裏邊有B鎖,B鎖裏邊有A鎖。

package com.lee.juc;

public class DeadLockTest {

	public static void main(String[] args) {
		DeadLock deadLock = new DeadLock();//flag = true
		
		Thread t1 = new Thread(deadLock);
		Thread t2 = new Thread(deadLock);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		deadLock.flag = false;
		t2.start();
		
	}
	
}

class DeadLock implements Runnable{
	
	public boolean flag = true;
	private Object obj = new Object();
	
	public DeadLock() {}
	
	public DeadLock(boolean flag) {
		this.flag = flag;
	}

	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this) {
					System.out.println("...if...this...lock.."+Thread.currentThread().getName());
					synchronized (obj) {
						System.out.println("...if...obj...lock.."+Thread.currentThread().getName());
					}
				}
			}
			
		}else {
			
			while(true) {
				synchronized (obj) {
					System.out.println("...else...obj...lock.."+Thread.currentThread().getName());
					synchronized (this) {
						System.out.println("...else...this...lock.."+Thread.currentThread().getName());
					}
				}
			}
			
		}
		
		
	}
	
}

結果:

相關文章
相關標籤/搜索