Java執行緒:什麼是執行緒
多工:同一時刻執行多個程式的能力。每一個任務稱為一個執行緒。可以同時執行一個以上執行緒的程式稱為多執行緒程式。
Java編寫程式都執行在在Java虛擬機器(JVM)中,在JVM的內部,程式的多工是通過執行緒來實現的。每用java命令啟動一個java應用程式,就會啟動一個JVM程序。在同一個JVM程序中,有且只有一個程序,就是它自己。在這個JVM環境中,所有程式程式碼的執行都是以執行緒來執行。
一般常見的Java應用程式都是單執行緒的。比如,用java命令執行一個最簡單的HelloWorld的Java應用程式時,就啟動了一個JVM程序,JVM找到程式程式的入口點main(),然後執行main()方法,這樣就產生了一個執行緒,這個執行緒稱之為主執行緒。當main方法結束後,主執行緒執行完成。JVM程序也隨即退出 。
對於一個程序中的多個執行緒來說,多個執行緒共享程序的記憶體塊,當有新的執行緒產生的時候,作業系統不分配新的記憶體,而是讓新執行緒共享原有的程序塊的記憶體。因此,執行緒間的通訊很容易,速度也很快。不同的程序因為處於不同的記憶體塊,因此程序之間的通訊相對困難。
程序是指一個記憶體中執行的應用程式,每個程序都有自己獨立的一塊記憶體空間,一個程序中可以啟動多個執行緒。比如在Windows系統中,一個執行的exe就是一個程序。
執行緒是指程序中的一個執行流程,一個程序可以執行多個執行緒。比如java.exe程序可以執行很多執行緒。執行緒總是輸入某個程序,程序中的多個執行緒共享程序的記憶體。
1 package Thread; 2 import java.awt.*; 3 import java.awt.event.*; 4 import javax.swing.*; 5 public class BounceThread { 6 public static void main(String[] args){ 7 EventQueue.invokeLater(new Runnable(){ 8 public void run(){ 9 JFrame frame=new BounceFrame(); 10 frame.setTitle("BounceFrame"); 11 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 12 frame.setVisible(true); 13 } 14 }); 15 } 16 } 17 /*class BallRunnable implements Runnable{ 18 private Ball ball; 19 private Component component; 20 public static final int STEPS=1000; 21 public static final int DELAY=5; 22 public BallRunnable(Ball aBall,Component aComponent){ 23 ball=aBall; 24 component=aComponent; 25 } 26 public void run(){ 27 try{ 28 for(int i=1;i<=STEPS;i++){ 29 ball.move(component.getBounds()); 30 component.repaint(); 31 Thread.sleep(DELAY); 32 } 33 } 34 catch(InterruptedException e){} 35 } 36 }*/ 37 class BounceFrame extends JFrame{ 38 private BallComponent comp; 39 public static final int STEPS=1000; 40 public static final int DELAY=100; 41 public BounceFrame(){ 42 comp=new BallComponent(); 43 add(comp,BorderLayout.CENTER); 44 JPanel buttonPanel=new JPanel(); 45 addButton(buttonPanel,"Start",new ActionListener(){ 46 public void actionPerformed(ActionEvent event){ 47 addBall(); 48 } 49 }); 50 addButton(buttonPanel,"Close",new ActionListener(){ 51 public void actionPerformed(ActionEvent event){ 52 System.exit(0); 53 } 54 }); 55 add(buttonPanel,BorderLayout.SOUTH); 56 pack(); 57 } 58 public void addButton(Container c,String title,ActionListener listener){ 59 JButton button=new JButton(title); 60 c.add(button); 61 button.addActionListener(listener); 62 } 63 /*public void addBall(){ 64 Ball b=new Ball(); 65 comp.add(b); 66 Runnable r=new BallRunnable(b,comp); 67 Thread t=new Thread(r); 68 t.start(); 69 }*/ 70 public void addBall(){ 71 try{ 72 Ball ball=new Ball(); 73 comp.add(ball); 74 for(int i=1;i<=STEPS;i++){ 75 ball.move(comp.getBounds()); 76 comp.paint(comp.getGraphics()); 77 Thread.sleep(DELAY); 78 } 79 } 80 catch(InterruptedException e){} 81 } 82 }View Code
BollComponent.java
1 package Thread; 2 import java.awt.*; 3 4 import java.util.*; 5 import javax.swing.*; 6 public class BallComponent extends JPanel{ 7 private static final int DEFAULT_WIDTH=450; 8 private static final int DEFAULT_HEIGHT=350; 9 private java.util.List<Ball>balls=new ArrayList<>(); 10 public void add(Ball b){ 11 balls.add(b); 12 } 13 public void paintComponent(Graphics g){ 14 super.paintComponent(g); 15 Graphics2D g2=(Graphics2D)g; 16 for(Ball b:balls){ 17 g2.fill(b.getShape()); 18 } 19 } 20 public Dimension getPreferredSize(){ 21 return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT); 22 } 23 }View Code
Ball.java
1 package Thread; 2 import java.awt.geom.*; 3 import java.awt.geom.Ellipse2D.Double; 4 public class Ball { 5 private static final int XSIZE=15; 6 private static final int YSIZE=15; 7 private double x=0; 8 private double y=0; 9 private double dx=1; 10 private double dy=1; 11 public void move(Rectangle2D bounds){ 12 x+=dx; 13 y+=dy; 14 if(x<bounds.getMinX()){ 15 x=bounds.getMinX(); 16 dx=-dx; 17 } 18 if(x+XSIZE>=bounds.getMaxX()){ 19 x=bounds.getMaxX()-XSIZE; 20 dx=-dx; 21 } 22 if(y<bounds.getMinY()){ 23 y=bounds.getMinY(); 24 dy=-dy; 25 } 26 if(y+YSIZE>=bounds.getMaxY()){ 27 y=bounds.getMaxY()-YSIZE; 28 dy=-dy; 29 } 30 } 31 public Ellipse2D getShape(){ 32 return new Ellipse2D.Double(x,y,XSIZE,YSIZE); 33 } 34 }View Code
針對上述的情況,下面的程式碼是改進後的,當點選close時,就會退出當前執行緒。而且不論何時點選Start按鈕,addBall都會啟動一個新執行緒.
實現多個執行緒的方法:將移動球的程式碼放置在一個獨立的執行緒中,點選開始就會重新啟動一個執行緒。簡單過程如下:
1、將任務程式碼放在實現了Runnable介面的類的run方法中。
1 class MyRunnable implements Runnable{ 2 public void run(){ 3 task code 4 } 5 }
2、建立一個類物件。Runnable r=new MyRunnable();
3、由Runnable建立一個Thread物件。Thread t=new Thread();
4、啟動執行緒:t.start();
BounceThread.java
1 package Thread; 2 import java.awt.*; 3 import java.awt.event.*; 4 import javax.swing.*; 5 public class BounceThread { 6 public static void main(String[] args){ 7 EventQueue.invokeLater(new Runnable(){ 8 public void run(){ 9 JFrame frame=new BounceFrame(); 10 frame.setTitle("BounceFrame"); 11 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 12 frame.setVisible(true); 13 } 14 }); 15 } 16 } 17 class BallRunnable implements Runnable{ 18 private Ball ball; 19 private Component component; 20 public static final int STEPS=1000; 21 public static final int DELAY=5; 22 public BallRunnable(Ball aBall,Component aComponent){ 23 ball=aBall; 24 component=aComponent; 25 } 26 public void run(){ 27 try{ 28 for(int i=1;i<=STEPS;i++){ 29 ball.move(component.getBounds()); 30 component.repaint(); 31 Thread.sleep(DELAY); 32 } 33 } 34 catch(InterruptedException e){} 35 } 36 } 37 class BounceFrame extends JFrame{ 38 private BallComponent comp; 39 //public static final int STEPS=1000; 40 //public static final int DELAY=100; 41 public BounceFrame(){ 42 comp=new BallComponent(); 43 add(comp,BorderLayout.CENTER); 44 JPanel buttonPanel=new JPanel(); 45 addButton(buttonPanel,"Start",new ActionListener(){ 46 public void actionPerformed(ActionEvent event){ 47 addBall(); 48 } 49 }); 50 addButton(buttonPanel,"Close",new ActionListener(){ 51 public void actionPerformed(ActionEvent event){ 52 System.exit(0); 53 } 54 }); 55 add(buttonPanel,BorderLayout.SOUTH); 56 pack(); 57 } 58 public void addButton(Container c,String title,ActionListener listener){ 59 JButton button=new JButton(title); 60 c.add(button); 61 button.addActionListener(listener); 62 } 63 public void addBall(){ 64 Ball b=new Ball(); 65 comp.add(b); 66 Runnable r=new BallRunnable(b,comp); 67 Thread t=new Thread(r); 68 t.start(); 69 } 70 /*public void addBall(){ 71 try{ 72 Ball ball=new Ball(); 73 comp.add(ball); 74 for(int i=1;i<=STEPS;i++){ 75 ball.move(comp.getBounds()); 76 comp.paint(comp.getGraphics()); 77 Thread.sleep(DELAY); 78 } 79 } 80 catch(InterruptedException e){} 81 }*/ 82 }View Code
BollComponent.java
1 package Thread; 2 import java.awt.*; 3 4 import java.util.*; 5 import javax.swing.*; 6 public class BallComponent extends JPanel{ 7 private static final int DEFAULT_WIDTH=450; 8 private static final int DEFAULT_HEIGHT=350; 9 private java.util.List<Ball>balls=new ArrayList<>(); 10 public void add(Ball b){ 11 balls.add(b); 12 } 13 public void paintComponent(Graphics g){ 14 super.paintComponent(g); 15 Graphics2D g2=(Graphics2D)g; 16 for(Ball b:balls){ 17 g2.fill(b.getShape()); 18 } 19 } 20 public Dimension getPreferredSize(){ 21 return new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT); 22 } 23 }View Code
Ball.java
1 package Thread; 2 import java.awt.geom.*; 3 import java.awt.geom.Ellipse2D.Double; 4 public class Ball { 5 private static final int XSIZE=15; 6 private static final int YSIZE=15; 7 private double x=0; 8 private double y=0; 9 private double dx=1; 10 private double dy=1; 11 public void move(Rectangle2D bounds){ 12 x+=dx; 13 y+=dy; 14 if(x<bounds.getMinX()){ 15 x=bounds.getMinX(); 16 dx=-dx; 17 } 18 if(x+XSIZE>=bounds.getMaxX()){ 19 x=bounds.getMaxX()-XSIZE; 20 dx=-dx; 21 } 22 if(y<bounds.getMinY()){ 23 y=bounds.getMinY(); 24 dy=-dy; 25 } 26 if(y+YSIZE>=bounds.getMaxY()){ 27 y=bounds.getMaxY()-YSIZE; 28 dy=-dy; 29 } 30 } 31 public Ellipse2D getShape(){ 32 return new Ellipse2D.Double(x,y,XSIZE,YSIZE); 33 } 34 }View Code
執行結果如下: