Java线程:什么是线程
一 基本概念
多任務:同一時刻運行多個程序的能力。每一個任務稱為一個線程。可以同時運行一個以上線程的程序稱為多線程程序。
Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是通過線程來實現的。每用java命令啟動一個java應用程序,就會啟動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環境中,所有程序代碼的運行都是以線程來運行。
一般常見的Java應用程序都是單線程的。比如,用java命令運行一個最簡單的HelloWorld的Java應用程序時,就啟動了一個JVM進程,JVM找到程序程序的入口點main(),然后運行main()方法,這樣就產生了一個線程,這個線程稱之為主線程。當main方法結束后,主線程運行完成。JVM進程也隨即退出 。
對于一個進程中的多個線程來說,多個線程共享進程的內存塊,當有新的線程產生的時候,操作系統不分配新的內存,而是讓新線程共享原有的進程塊的內存。因此,線程間的通信很容易,速度也很快。不同的進程因為處于不同的內存塊,因此進程之間的通信相對困難。
進程是指一個內存中運行的應用程序,每個進程都有自己獨立的一塊內存空間,一個進程中可以啟動多個線程。比如在Windows系統中,一個運行的exe就是一個進程。
線程是指進程中的一個執行流程,一個進程可以運行多個線程。比如java.exe進程可以運行很多線程。線程總是輸入某個進程,進程中的多個線程共享進程的內存。
Java中線程是指java.lang.Thread類的一個實例或線程的執行。使用java.lang.Thread或java.lang.Runnable接口編寫代碼定義、實例化、啟動新線程。
Java中每個線程都有一個調用棧,即使不在程序中創建任何新的線程,線程也在后臺運行。main()方法運行在一個線程內,稱為主線程。一旦創建一個新的線程,就產生一個新的調用棧。
線程分為兩類:用戶線程和守候線程。當所有用戶線程執行完畢后,JVM自動關閉。但是守候線程卻不獨立與JVM,守候線程一般是有操作系統或用戶自己創建的。
二 定義線程
1 擴展java.lang.Thread類以及實現java.lang.Runnable接口。
此類中有run()方法,public void run(),如果該線程是獨立的Runnable運行對象構造的,則調用該Runnable對象的run()方法;否則,該方法不執行任何操作。Thread的子類也應該重寫該方法。
三 實例化線程
1 如果是擴展了java.lang.Thread類的線程,則直接調用new即可。
2 如果是實現了jav.lang.Runnable接口的類,則調用Thread的構造方法:
Thread(Runnable target)
Thread(Runnable target,String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
四 啟動線程
在線程的Thread對象上調用start()方法,而不是run()或別的方法。
在調用start()方法之前,線程處于新狀態中,新狀態有一個Thread對象,但沒有一個真正的線程。
在調用start()方法之后,發生了一系列復雜的事情:
啟動新的執行線程(具有新的調用棧);
該線程從新狀態轉移到可運行狀態;
當該線程獲得執行機會時,其目標run()方法將運行。
五 注意事項
1獲取當前線程的對象的方法是:Thread.currentThread();
2當線程目標run()方法結束時該線程完成。
3一旦線程啟動,它就永遠不能再重新啟動。只有一個新的線程可以被啟動,并且只能一次。一個可運行的線程或死線程可以被重新啟動。
4線程的調度是JVM的一部分,在一個CPU的機器上上,實際上一次只能運行一個線程。一次只有一個線程棧執行。JVM線程調度程序決定實際運行哪個處于可運行狀態的線程。眾多可運行線程中的某一個會被選中做為當前線程。可運行線程被選擇運行的順序是沒有保障的。
5盡管通常采用隊列形式,但這是沒有保障的。隊列形式是指當一個線程完成“一輪”時,它移到可運行隊列的尾部等待,直到它最終排隊到該隊列的前端為止,它才能被再次選中。事實上,我們把它稱為可運行池而不是一個可運行隊列,目的是幫助認識線程并不都是以某種有保障的順序排列一個隊列的事實。
6盡管我們沒有無法控制線程調度程序,但可以通過別的方式來影響線程調度的方式。
六 示例
當點擊start按鈕時,程序從屏幕左上角彈出一個球,這個球開始移動,調用addBall方法,循環運行1000次move。每調用一次move,球就會移動一點,當碰到墻壁時,就會調整方向,但是這個程序有個弊端:當你想在移動1000次之前,就想退出程序,點擊close發現,其仍在移動。
Thread類的靜態方法sleep()將暫停給定的毫秒數。調用Thread.sleep不會創建一個新線程,sleep是Thread類的靜態方法,用于暫停當前線程活動。
Bounce.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
針對上述的情況,下面的代碼是改進后的,當點擊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
運行結果如下:
當神已無能為力,那便是魔渡眾生
總結
以上是生活随笔為你收集整理的Java线程:什么是线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 能源自由的终极追求 核聚变投资暴涨:最快
- 下一篇: 高阶篇:4.2.4)DFMEA严重度S(