Thread實現多執行緒、死鎖、同步鎖
1、實現一個類MyThread繼承Thread並重寫run()方法 啟動執行緒方法:例項化MyThread物件,並呼叫start()方法 多個執行緒之間交替執行(搶時間片) 主執行緒(main方法)有優先執行的許可權,但並不絕對
2、實現一個類MyThread實現Runnable介面下的run()方法 啟動執行緒方法:例項化MyThread物件mt,並將mt作為例項化Thread的引數,再通過Thread物件呼叫start()方法 MyThread mt = new MyThread(); Thread t = new Thread(mt); t.start();
實現點選按鈕,球向前慢慢滾動的效果: public class Test extends JFrame{
private MyPanel mp; public static void main(String[] args) { new Test().setVisible(true);
} private JPanel panel; private JButton btn; public Test() { this.setDefaultCloseOperation(EXIT_ON_CLOSE); panel = new JPanel(); panel.setLayout(new BorderLayout()); setBounds(300, 100, 600, 300); this.setContentPane(panel); mp = new MyPanel(); panel.add(mp); btn = new JButton("開始"); btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Thread t = new Thread(mp); t.start(); } }); panel.add(btn,BorderLayout.SOUTH); } private class MyPanel extends JPanel implements Runnable{
private int x = 100; public void paint(Graphics g) { super.paint(g); g.fillOval(x, 80, 50, 50); } @Override public void run() { for (int i = 0; i < 50; i++) { x += 5 ; try { Thread.sleep(150); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } repaint(); } } } }
3、使用匿名類,繼承Thread,重寫run()方法,直接在run()方法中寫業務程式碼 匿名類的一個好處是可以很方便的訪問外部的區域性變數 public class TestThread { public static void main(String[] args) { Hero gareen = new Hero(); gareen.name = "蓋倫"; gareen.hp = 616; gareen.damage = 50; Hero teemo = new Hero(); teemo.name = "提莫"; teemo.hp = 300; teemo.damage = 30; Hero bh = new Hero(); bh.name = "賞金獵人"; bh.hp = 500; bh.damage = 65; Hero leesin = new Hero(); leesin.name = "盲僧"; leesin.hp = 455; leesin.damage = 80; //匿名類 Thread t1= new Thread(){ public void run(){ //匿名類中用到外部的區域性變數teemo,必須把teemo宣告為final //但是在JDK7以後,就不是必須加final的了 while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; t1.start(); Thread t2= new Thread(){ public void run(){ while(!leesin.isDead()){ bh.attackHero(leesin); } } }; t2.start(); } }
注意: 啟動執行緒是start()方法,run()並不能啟動一個新的執行緒
常見執行緒方法:
sleep 當前執行緒暫停 Thread.sleep(1000); 表示當前執行緒暫停1000毫秒 ,其他執行緒不受影響
join 加入到當前執行緒中 Thread t1= new Thread(){ public void run(){ while(!teemo.isDead()){ gareen.attackHero(teemo); } } }; t1.start(); try { //main執行緒在執行時,t1執行緒加入到main執行緒中來,只有t1執行緒執行結束,才會繼續往下走 t1.join(); } catch (InterruptedException e) { e.printStackTrace();
}
setPriority 執行緒優先順序 當執行緒處於競爭關係的時候,優先順序高的執行緒會有更大的機率獲得CPU資源 Thread t1 = new Thread(); Thread t2 = new Thread(); t1.setPriority(Thread.MAX_PRIORITY);最大為10 t2.setPriority(Thread.MIN_PRIORITY);最小為0
yield 臨時暫停 當前執行緒,臨時暫停,使得其他執行緒可以有更多的機會佔用CPU資源
setDaemon 守護執行緒 如果一個程序只剩下守護執行緒,那麼程序就會自動結束。
執行緒同步
沒有實現同步 public class Bank {
public static void main(String[] args) { new Bank().way();
}
public void way() { Family f = new Family(); Thread t1 = new Thread(f, "丈夫");
//new Thread(f, "執行緒名稱"); Thread t2 = new Thread(f, "妻子"); t1.start(); t2.start(); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } while (true) { if (f.times >= 2) { f.show(); break; } }
}
private class Family implements Runnable { private int totalMoney; private int getMoney; private int currentMoney; private int times = 0; private Object key = new Object();
public Family() { totalMoney = 5000; getMoney = 2000; currentMoney = 0; }
@Override public void run() {
//Thread.currentThread()當前執行緒 System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元"); //給取出的錢重新賦值 currentMoney += getMoney; //銀行存款剩餘 int tem = totalMoney - getMoney; //在銀行存款變換之前,執行緒沉睡1s,這時,時間片被另一個執行緒搶走 try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //給銀行存款重新賦值 totalMoney = tem; times++; } public void show() { System.out.println("銀行存款剩餘:" + totalMoney + "\t取出:" + currentMoney); } } } 執行: 丈夫---取了2000元 妻子---取了2000元 銀行存款剩餘:3000 取出:4000
新增同步鎖: 方法一: //物件必須在run()方法體外面 private Object key = new Object();
public void run() { //synchronized( 可以是任意物件,例如:this) synchronized (key) { System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元"); currentMoney += getMoney; int tem = totalMoney - getMoney; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } totalMoney = tem; times++; }
}
方法二: public void run() { syn();
} public synchronized void syn() { System.out.println(Thread.currentThread().getName() + "---取了" + getMoney + "元"); currentMoney += getMoney; int tem = totalMoney - getMoney; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } totalMoney = tem; times++; } 執行: 丈夫---取了2000元 妻子---取了2000元 銀行存款剩餘:1000 取出:4000
死鎖
1. 執行緒1 首先佔有物件1,接著試圖佔有物件2 2. 執行緒2 首先佔有物件2,接著試圖佔有物件1 3. 執行緒1 等待執行緒2釋放物件2 4. 與此同時,執行緒2等待執行緒1釋放物件1 就會。。。一直等待下去,直到天荒地老,海枯石爛,山無稜 ,天地合。。。
public class Test04 {
public static void main(String[] args) { new Test04();
} public Test04() { MyThread mt = new MyThread(); Thread t1 = new Thread(mt,"A"); Thread t2 = new Thread(mt,"B"); t1.start();t2.start(); } public class MyThread implements Runnable{ private Object o1 = new Object(); private Object o2 = new Object(); private boolean b = false; @Override public void run() { if(b) { b = !b; synchronized (o1) { System.out.println(Thread.currentThread().getName()+"拿到第一把鑰匙!"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (o2) { System.out.println(Thread.currentThread().getName()+"拿到第二把鑰匙!"); } } }else { b = !b; synchronized (o2) { System.out.println(Thread.currentThread().getName()+"拿到第二把鑰匙!"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (o1) { System.out.println(Thread.currentThread().getName()+"拿到第一把鑰匙!"); } } } } }
} 執行: B拿到第一把鑰匙! A拿到第二把鑰匙! (一直在執行中,程式沒有結束!)