一、進程:正在進行中的程序
二、線程:就是進程中一個負責程序執行的控制單元(執行路徑)java
一個進程中,能夠有多個執行路徑,即多線程小程序
一個進程中,至少有一個執行路徑。安全
(多線程其實就是多個線程中的快速切換)多線程
繼承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 返回當前正在執行線程的引用對象
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的侷限性
===========================
再增長一個臨時阻塞狀態
需求:四個窗口共同賣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; } } } }
結果:
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; } } } }
結果:
產生緣由:
①、多個線程,操做同一個共享數據
②、操做共享數據的線程代碼有多條
就是將多條操做共享數據的線程代碼封裝起來,當有線程在執行這些代碼的時候,其餘線程不能夠參與運算。
必需要當前線程把這些代碼都執行完後,其餘線程才能執行。
同步代碼塊的格式:
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; } } //===================== } } }
結果:
同步的好處和弊端:
好處:解決了線程安全的問題
弊端:相對下降了效率
注:
必須保證多個線程使用同一個鎖
需求:
兩個儲戶去銀行存錢,每一個人存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); } } }
結果:
一、驗證是不是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
代碼:
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
//懶漢式 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; } }
產生情景:
一、同步的嵌套: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()); } } } } } }
結果: