多執行緒學習筆記(狂神說視訊15-20)
阿新 • • 發佈:2020-08-24
觀測執行緒狀態
public class TestState { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("......"+i+"......"); } }); //觀察狀態 Thread.State state = t.getState(); System.out.println(state); //觀察啟動後 t.start();//啟動執行緒 state = t.getState(); System.out.println(state); while (state!=Thread.State.TERMINATED){//執行緒不是終止狀態 Thread.sleep(100); state = t.getState();//更新狀態 System.out.println(state); } t.start();//停止之後就不能啟動了 } }
執行結果
執行緒的優先順序(priority)
執行緒優先順序高,不一定先呼叫
//測試執行緒的優先順序 public class TestPriority { public static void main(String[] args) { //主執行緒預設的優先順序 System.out.println(Thread.currentThread().getName()+"->"+Thread.currentThread().getPriority()); MyPriority m =new MyPriority(); Thread t1 = new Thread(m); Thread t2 = new Thread(m); Thread t3 = new Thread(m); Thread t4 = new Thread(m); Thread t5 = new Thread(m); Thread t6 = new Thread(m); Thread t7 = new Thread(m); //先設定優先順序,再啟動 t1.start();//不設定預設是5 t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY);//=10 t4.start(); t5.setPriority(7); t5.start(); t6.setPriority(9); t6.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"->"+Thread.currentThread().getPriority()); } }
執行結果
守護執行緒(daemon)
//測試守護執行緒 //上帝守護你 public class TestDaemon { public static void main(String[] args) { You1 you1 = new You1(); God god = new God(); Thread thread = new Thread(god); thread.setDaemon(true);//預設false是使用者執行緒,正常的執行緒都是使用者執行緒 thread.start();//上帝守護執行緒啟動 new Thread(you1).start();//你 使用者執行緒啟動 } } //你 class You1 implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("你開心的活了"+i+"歲"); } System.out.println("Goodbye World!"); } } //上帝 class God implements Runnable{ @Override public void run() { while (true){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("上帝守護著你"); } } }
執行結果
執行緒同步機制
併發:同一個物件被多個執行緒同時操作
執行緒同步:其實就是一種等待機制,多個需要同時訪問此物件的執行緒進入這個物件的等待池形成佇列,等待前面執行緒使用完畢,下一個執行緒再使用。
三大不安全案例
不安全的買票
public class UnsafeBuyTiket {
public static void main(String[] args) {
// TODO Auto-generated method stub
BuyTicket station = new BuyTicket();
new Thread(station,"苦逼的我").start();
new Thread(station,"牛逼的大家").start();
new Thread(station,"可惡的黃牛").start();
}
}
class BuyTicket implements Runnable{
//票
private int ticketNums = 10;
boolean flag = true;//外部停止方式
@Override
public void run() {
//買票
while(flag)
{
try{
buy();
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
private void buy() throws InterruptedException{
//判斷是否有票
if(ticketNums<=0)
{
return;
}
//模擬延時
Thread.sleep(100);
//買票
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--+"票");
}
}
執行結果
出現了重複的票
不安全的取錢
//兩個人去銀行取錢,賬戶
public class UnsafeBank {
public static void main(String[] args) {
Account a = new Account(100,"結婚基金");
Drawing you = new Drawing(a,50,"你");
Drawing girl = new Drawing(a,100,"girl");
you.start();
girl.start();
}
}
//賬戶
class Account{
int money;//餘額
String name;//卡名
public Account(int money,String name)
{
this.money = money;
this.name = name;
}
}
//銀行:模擬取款
class Drawing extends Thread{
Account account;//賬戶
int drawingMoney;//取了多少錢
int nowMoney;//現在手裡有多少錢
public Drawing(Account account,int drawingMoney,String name) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取錢
@Override
public void run() {
//判斷有沒有錢
if(account.money-drawingMoney<0)
{
System.out.println(Thread.currentThread().getName()+"錢不夠");
return;
}
//sleep可以放大問題的發生性
try {
Thread.sleep(1000);
}catch(Exception e)
{
e.printStackTrace();
}
//卡內餘額=餘額-你取的錢
account.money = account.money-drawingMoney;
//你手裡的錢
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"餘額為"+account.money);
//這兩個操作等價
//System.out.println(this.getName()+Thread.currentThread().getName());
System.out.println(this.getName()+"手裡的錢"+nowMoney);
}
}
執行結果
出現了-50
不安全的集合
public class UnsafeList {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = new ArrayList<String>();
for(int i=0;i<10000;i++)
{
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
}catch(Exception e)
{
e.printStackTrace();
}
System.out.println(list.size());
}
}
執行結果
不足10000,因為存在兩個執行緒同時看到一個標誌,於是name就被覆蓋掉了
同步方法及同步塊(synchronized)
把不安全的改成安全的
同步的取票
//同步方法,鎖的是this
private synchronized void buy() throws InterruptedException{
//判斷是否有票
if(ticketNums<=0)
{
return;
}
//模擬延時
Thread.sleep(100);
//買票
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--+"票");
}
執行結果
同步的取款
//取錢
@Override
public void run() {
synchronized(account)
{
//判斷有沒有錢
if(account.money-drawingMoney<0)
{
System.out.println(Thread.currentThread().getName()+"錢不夠");
return;
}
//sleep可以放大問題的發生性
try {
Thread.sleep(1000);
}catch(Exception e)
{
e.printStackTrace();
}
//卡內餘額=餘額-你取的錢
account.money = account.money-drawingMoney;
//你手裡的錢
nowMoney = nowMoney + drawingMoney;
System.out.println(account.name+"餘額為"+account.money);
//這兩個操作等價
//System.out.println(this.getName()+Thread.currentThread().getName());
System.out.println(this.getName()+"手裡的錢"+nowMoney);
}
}
執行結果
同步的集合
for(int i=0;i<10000;i++)
{
new Thread(()->{
synchronized(list)
{
list.add(Thread.currentThread().getName());
}
}).start();
}