进程与线程
进程是程序的一次动态执行过程,它经历了从代码加载、执行、执行结束的一个完整过程,这个过程也是整个进程的生命周期。
多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发机制的基本单位。
传统的单核CPU在同一个时间段可以有多个程序在执行,但是只能有一个程序在某一时间点运行,所有的程序都要抢占CPU资源。
多核CPU下程序会并发执行。
Java中多线程的实现
Java中要实现多线程可以通过以下两种方式:
1.继承Thread类
2.实现Runnable接口
1.继承Thread类
继承的Thread类定义在java.lang包,一个类只要继承了Thread类就必须覆写Thread类中的run方法,该方法为线程的主体。
实例:
class MyThread extends Thread {
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { // 覆写run方法,作为线程操作的主体
for (int i = 0; i < 3; i++) {
System.out.println(name + "test i=:" + i);
}
}
}
public class ThreadTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.run();
mt2.run();
}
}
但是从运行结果来看, 该程序没有达到并发执行的效果,因为调用方法时用的依然是对象.方法的格式。要想让它们并发执行,要调用Thread类中的start方法。
调用改动不大, 此处略。
改动后可以看到两个程序是并发执行的。
2.实现Runnable接口
启动线程需要依靠Thread类,如果之前继承了Thread类,可以直接使用start方法,但是在Runnable接口中没有该方法。
Thread类的构造是:public Thread(Runnable target)
利用以上的构造方法启动多线程。
class MyThread implements Runnable {
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { // 覆写run方法,作为线程操作的主体
for (int i = 0; i < 10; i++) {
System.out.println(name + "test i=:" + i);
}
}
}
public class ThreadTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
Thread t1 = new Thread(mt1);
Thread t2 = new Thread(mt2);
t1.start();
t2.start();
}
}
Thread类和Runnable接口的关系
API中可以看到,Thread类也是Runnable接口的子类。
Runnable
接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run
的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread
类实现了 Runnable
。激活的意思是说某个线程已启动并且尚未停止。
Thread类和Runnable接口的区别
使用Thread类不能达到资源共享的目的,而使用Runnable类可以实现资源共享的目的。
卖票实例:
Thread:
class MyThread extends Thread {
private int ticket = 5;
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { // 覆写run方法,作为线程操作的主体
for (int i = 0; i < 10; i++) {
if (ticket > 0) {
System.out.println(name + "test i=:" + ticket);
ticket--;
}
}
}
}
public class ThreadTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mt1 = new MyThread("线程A");
MyThread mt2 = new MyThread("线程B");
mt1.start();
mt2.start();
}
}
Runnable:
class MyThread implements Runnable {
private int ticket = 5;
private String name;
public MyThread(String name) {
this.name = name;
}
public void run() { // 覆写run方法,作为线程操作的主体
for (int i = 0; i < 10; i++) {
if (ticket > 0) {
System.out.println(name + "test i=:" + ticket);
ticket--;
}
}
}
}
public class ThreadTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mt1 = new MyThread("线程A");
Thread t1 = new Thread(mt1);
t1.run();
t1.run();
t1.run();
}
}
可见Runnable接口可以实现资源共享。
总结:Runnable接口比继承Thread类有更大的优点:1.适合用多个相同程序的代码处理同一个资源。2.可以避免单继承局限带来的影响 3.代码能被多个进程共享,代码与数据是独立的。
线程的状态
创建状态:准备好了一个多线程对象
就绪:调用了Start方法,等待调度(start方法是准备开始,还要等待CPU调度,其实就是执行run方法)
运行:执行run方法;
阻塞,暂停:暂停本线程,交给其他线程;
终止:线程执行完毕,不再使用。