要了解线程,先要了解进程。简单的理解,
进程就是一个正在执行的程序。而一个
进程可能执行着多条线程,比如一个下载软件正在下一个文件,它可能把文件分为几个部分,每一部分又分配一个线程负责下载。又比如,一台电脑,同时运行着浏览器,QQ,播放器等等好多应用程序,也是通过一个个线程来完成的。
那么线程是否是同时运行的吗?不是的,
一个CPU,在同一个时间只能做一件事,只是它比较三心二意,一下子处理浏览器,一下子又去处理QQ,只是由于它的处理速度极快,使得所有应用程序的动作好像连贯一般。
而且线程有个优先级,谁的优先级高一点,cpu就对谁好一点。该线程被执行到的概率就大一点,但并不表示优先级低的线程不会被执行到。
说了这么多,那么如何实现应用程序的多线程呢?
方法一、直接继承Thread类,重写run()。
public class MyThread extends Thread {
public void run(){
.... //要在线程里运行的代码
}
}
方法二、实现Runnable接口。
public class MyThread implements Runnable {
public void run(){
... //要在线程里运行的代码
}
}
其实这两种方法的本质是一样的,都是要实现Runnable接口,察看Thread类的源码就可得知,Thread类本身就是实现了Runnable接口。最主要的一点是,无论用什么方法,我们都是在它们的run()方法中执行我们的代码。
首先了解一下
线程常用的方法。
start() 开始运行线程。
run() 线程要执行的代码。
sleep(long millis) 让线程睡眼millis毫秒时间,时间到后,线程重新进行就绪状态(并非马上开始)
yield() 线程让步,线程让出cpu,重新进入就绪状态
wait() 让线程暂停,谁来让它重新开始呢?参考notify(),notifyAll();
notify() 唤醒正在wait的线程,如果同时有多个线程在wait状态,则任意唤醒一个。
notifyAll() 唤醒正在wait的所有线程。
join() 线程在扫行的过程中,让其它线程加入执行后自己才执行。
首先看一个例子:
public class ThreadTest extends Thread {
public static void main(String[] args) {
//主线程开始
System.out.println("主线程开始。。。。。");
//子线程开始
new ThreadTest().start();
//在主线程运行一此代码
Thread t = Thread.currentThread();
for(int i=0; i<10; i++){
System.out.println("我是"+t.getName()+",我的id是"+t.getId());
}
}
@Override //在子线程中执行的代码
public void run() {
Thread t = Thread.currentThread();
for(int i=0; i<10; i++){
System.out.println("我是"+t.getName()+",我的id是"+t.getId());
}
}
}
运行的结果是不唯一的,多个线程执行,每时每刻线程都在抢着工作,抢一点工作一点,直到线程结束为止。那么线程什么时候算是停止了呢?这要了解一下 线程的生命周期。
1、创建完一个线程对象后,线程并未开始,此时处于
初始化新建状态。
2、当线程调用start()方法后,线程处于
就绪状态,但并没有开始执行run()方法的内容。
3、当线程抢到cpu后,则就开始执行run()方法,处于
运行状态。
4、当线程调用了sleep(),wait(),或者阻塞式的io方法,处于
阻塞状态。
5、当线程执行完run()方法后,或者发生异常,应该说是未捕获的异常,则线程处于
死亡状态。
下面是一个让方块在窗口内移动的例子,大家看一下多线程的使用。
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovingRect extends JPanel implements Runnable {
private int x = 10;
private int y = 10;
public static void main(String[] args) {
//设置窗口属性。
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(250, 50);
frame.add(new MovingRect());
frame.setVisible(true);
}
public MovingRect() {
//设置面板属性
this.setSize(800, 600);
this.setLocation(10, 10);
//创建子线程,并让它进入就绪状态。
Thread t = new Thread(this);
t.start();
this.setVisible(true);
}
@Override
public void paint(Graphics g) {
super.paint(g);
Color c = g.getColor();
g.setColor(Color.RED);
//画一个方块
g.fillRect(x, y, 15, 15);
g.setColor(c);
}
//子线程要做的就是更改方块的位置坐标,并刷新。
public void run() {
while (true) {
this.x += 8;
this.y += 6;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.repaint();
}
}
}