標籤:java 線程
線程:
static void sleep(long 毫秒):睡眠 在指定的毫秒數內讓正在執行的線程進入休眠狀態(暫停執行)
throws InterruptedException
注意:
1 線程休眠是協助所有線程獲得運行機會的最好的方法
2 線程睡眠自動蘇醒,並返回到就緒狀態(可運行),不是運行狀態。
sleep()指定的時間是休眠後可啟動並執行最短時間,
sleep()方法不能保證該線程到期後就開始運行
3 sleep()是靜態方法,只能控制當前正在啟動並執行線程。
線程的優先順序:層級越高,機會越多。層級越低機會越少,但是不絕對
最大:10 MAX_PRIORITY
小寫:1 MIN_PRIORITY
預設:5 NORM_PRIORITY
setPriority()
getPriority()
join():合并 表示當前線程等待該線程執行完畢,如果該線程未執行完前sleep了,其他線程將不再等待
static yield():當前線程讓步。只讓步一次,下一次是哪個線程不一定
void interrupt():中斷 修改線程中斷的標誌flag : false–>true
static boolean interrupted():是否被中斷的狀態 返回flag 擦除 true–>false
main(){
T1 t = new T1();
t.start();
//發出一個中斷訊號
t.interrupt();//Thread.interrupted() flag: false–>true
}
class T1 extends Thread{
public void run(){
while(!Thread.interrupted()){
….
//如果sleep()時候被中斷,會拋出異常
}
System.out.println(“子線程結束”);
}
}
同步:
資料不安全:
1 Runnable介面實現資料共用
2 run方法中共用語句由多行組成
3 run方法阻塞
同步機制:同步鎖
表示只能被一個線程執行,中間不能被打斷,其他線程只能等待
原理:其實就是鎖定一個對象
實現同步的方式:
1)同步代碼塊:
synchronized(鎖){
}//自動解鎖 種類: a 任意對象 Object obj = new Object();//聲明了一個鎖 synchronized(obj){ } b this:當前對象:將當前對象當成鎖 synchronized(this){ } 特殊: synchronized("abc"){ } byte[] b= new byte[]; synchronized(b){//0個長度的位元組數組 } c 運行時的鎖 靜態資料。靜態方法調用的時候使用運行時鎖 A.java-->A.class:jvm載入位元組碼檔案 synchronized(XXX.class){ } 2)同步方法:在方法前面加上synchronized關鍵字 同步非靜態方法,鎖定是this對象 同步靜態方法,鎖定是XXX.class對象 ----->同一時刻只有一個線程訪問該方法
執行個體:
public class Demo {
public static void main(String[] args) { TicketRunnable1 t = new TicketRunnable1(); Thread t1 = new Thread(t, "A"); Thread t2 = new Thread(t, "B"); t1.start(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t.flag = false; t2.start();}static class TicketRunnable1 implements Runnable { private int tickets = 10; private boolean flag = true; private static int sum = 10; @Override public void run() { if (flag) { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("sale" + sum--); } } else { while (true) t(); } } // 同步方法:鎖定this public synchronized void sale() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " ------ " + --tickets); } else { flag = false; } } // 注意方法的粒度 // 靜態同步方法:對Class進行加鎖,在同一時刻只有一個線程使用此方法 public static synchronized void t() {// TicketRunnable1.class if (sum > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " ------ " + --sum); } }}
}
死結:
由於A線程鎖住資源A,等待資源B。線程B鎖住了資源B,等待資源A,出現了死結
一個線程的同步代碼中啟動了另一個同步,兩個線程鎖交叉使用
執行個體:
public class Demo {
public static void main(String[] args) { MyRunnable mr = new MyRunnable(); mr.flag = true;// 張三 Thread t1 = new Thread(mr, "張三"); t1.start(); MyRunnable mr1 = new MyRunnable(); mr1.flag = false;// 李四 Thread t2 = new Thread(mr1, "李四"); t2.start();}static class MyRunnable implements Runnable { private static String bread = "麵包"; // 資源A private static String milk = "牛奶"; // 資源B boolean flag; // 切換 @Override public void run() { if (flag) { // 張三 synchronized (bread) { System.out.println(Thread.currentThread().getName() + "已經鎖定了麵包,還想要牛奶"); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (milk) { System.out.println(Thread.currentThread().getName() + "已經鎖定了麵包也擁有了牛奶"); } } } else { // 李四 synchronized (milk) { System.out.println(Thread.currentThread().getName() + "已經鎖定了牛奶,還想要麵包"); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (bread) { System.out.println(Thread.currentThread().getName() + "已經鎖定了牛奶也擁有了麵包"); } } } }}
}
生產者-消費者模式:
notify() notifyAll() wait()必須在同步鎖中才能出現。
通過鎖來指明讓持有該線程的對象去等待或者喚醒
Object類:
wait():讓線程進入等待狀態,放入了線程池,會釋放鎖
notify():喚醒等待的線程,喚醒線程池中任意一個線程
notifyAll():喚醒線程池中所有的線程
烤鴨
是否有產品:flag
1)沒有產品:
if(flag == false)//沒有烤鴨
生產者線程生產產品
flag = true;
消費者線程等待
等待():通知生產者生產產品
2)有產品
if(flag == true)
生產者線程:等待消費者消費
消費者線程:
消費
flag = false
生產者負責生產,有生產產品任務
消費者負責消費,有消費產品的任務
生產和消費同時進行—->多線程
執行個體:
public class Demo {
public static void main(String[] args) {
Duck d = new Duck();
Productor pro = new Productor(d);
Customer cus = new Customer(d);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(cus);
t1.start();
t2.start();
}
}
class Duck {
String name;
int price;
boolean flag; // 標誌
@Override
public String toString() {
return “烤鴨 [name=” + name + “, price=” + price + “, flag=” + flag + “]”;
}
}
// 生產者
class Productor implements Runnable {
Duck duck;
Productor(Duck duck) {
this.duck = duck;
}
@Override
public void run() {
while (true) {
synchronized (duck) {
if (duck.flag) {// 當前已經有生產好的烤鴨了
try {
duck.wait();// 等待消費
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 生產產品
duck.name = “北京烤鴨”;
duck.price = 298;
System.out.println(“———”);
System.out.println(“生產烤鴨:” + duck);
duck.flag = true; // 修改標誌:已經生產好了
// 喚醒消費者
duck.notify();
}
}
}
}
// 消費者
class Customer implements Runnable {
Duck duck;
Customer(Duck duck) {
this.duck = duck;
}
@Overridepublic void run() { while (true) { synchronized (duck) { if (!duck.flag) {// 沒有產品 try { duck.wait(); // 等待生產產品 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("吃烤鴨" + duck); System.out.println("-------------"); duck.flag = false;// 修改標誌 duck.notify(); } }}
}
public class Demo {
public static void main(String[] args) { Room wdm = new Room(); Pro p = new Pro(wdm); Cus c = new Cus(wdm); new Thread(p).start();// t1 new Thread(c).start(); // t2 new Thread(p).start(); // t3 new Thread(c).start(); // t4}
}
class Room {
private String name;
private int price;
private boolean flag;
public String getName() { return name;}public void setName(String name) { this.name = name;}public int getPrice() { return price;}public void setPrice(int price) { this.price = price;}public boolean isFlag() { return flag;}public void setFlag(boolean flag) { this.flag = flag;}public Room(String name, int price, boolean flag) { super(); this.name = name; this.price = price; this.flag = flag;}public Room() { super();}@Overridepublic String toString() { return "Room [name=" + name + ", price=" + price + ", flag=" + flag + "]";}// 生產麵包 p t1 t3 c t2 t4public synchronized void productBread(String name, int price) { // 已經有產品:while 而不是if while (flag) { try { // System.out.println("當前已經有產品,等待消費中...."); this.wait();// 等待 t1 t2 t3 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.name = name; this.price = price; System.out.println("生產麵包:" + name + " " + price); this.flag = true; this.notifyAll();// //////////////////////////}// 消費麵包public synchronized void buyBread() { while (!flag) {// 沒有麵包 try { // System.out.println("當前沒有生產好的麵包,等待中......"); this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("消費麵包:" + name + " " + price); this.flag = false;// 消費過了,沒有產品 this.notifyAll();}
}
// 生產者
class Pro implements Runnable {
Room r;
Pro(Room r) { this.r = r;}int i = 0;@Overridepublic void run() { while (true) { if (i % 2 == 0) { r.productBread("毛毛蟲", 7); } else { r.productBread("麵包", 10); } i++; }}
}
// 消費者
class Cus implements Runnable {
Room r;
Cus(Room r) { this.r = r;}@Overridepublic void run() { while (true) { r.buyBread(); }}
}
Lock:
synchronized:悲觀鎖。
lock:樂觀鎖。
synchronized(對象){//鎖定
}//釋放鎖
使用Lock介面對鎖進行單獨的描述。
1 建立Lock介面的一個子類—ReentrantLock
使用Lock替代同步代碼塊
2 需要同步的代碼放入lock()和unlock()之間
wait(),notify(),notifyAll()必須出現在同步代碼中
Condition介面中提供了相應的方法、
await() signal() signalAll()
線程池:Executor
建立單線程池對象
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new ThreadRunnable());
executor.execute(new ThreadRunnable());
建立同時可以執行的2個線程
Executor e = Executors.newFixedThreadPool(2);
e.execute(new ThreadRunnable());
e.execute(new ThreadRunnable());
e.execute(new ThreadRunnable());
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Java基礎 筆記(五)