当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。
独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间。
动态性:进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念。进程具有自己的生命 周期和各种不同的状态,这些概念在程序中都是不具备的。
并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会互相影响。
大部分操作系统都支持多进程并发运行,并发编程可以将程序划分为多个分离的,独立运行的任务。通过使用多线程机制,这些独立任务中的每一个都将由执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,因此,单个进程可以拥有多个并发执行的任务,其底层机制是切分CPU时间。在使用线程时,CPU将轮流给每个任务分配占用时间,划分成片段分配给所有任务,当然,也有个例外情况,就是该程序确实运行在多个CPU之上。总而言之,操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。
实现线程主要有两种方式:
- 实现Runnable接口
线程可以驱动任务,想要定义任务,只需要实现Runnable接口并编写run()方法,使该任务可以执行命令,如:
public class Demo implements Runnable {
protected int count = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public Demo() {
}
public Demo(int count) {
this.count = count;
}
public String status(){
return "倒计时" + id + "(" + (count > 0 ? count : "go") + "),";
}
@Override
public void run() {
while(count --> 0){
System.out.println(status());
Thread.yield();
}
}
}
该例子将显示发射之前的倒计时,final修饰的id可以用来区分任务的多个实例,run()方法中对静态方法Thread.yield()的调用是Java线程机制的一部分,可以将CPU从一个线程转移给另外一个线程,通俗点说,就是已经执行完该程序生命周期中最重要的部分,可以将CPU的占用切换给其他任务执行一段时间。
例子:
public class RunDemo {
public static void main(String[] args) {
Demo demo = new Demo();
demo.run();
}
}
输出结果:
该例子中的run()不是由单独的线程驱动的,是在main()中直接调用,实际上,该例子仍然使用了线程,即总是分配给main()的那个线程。当从Runnable 导出的一个类时,它必须具有run()方法,该方法不会产生任何内在的线程能力,要实现线程行为,必须显式地将一个任务附在到线程上。
2.继承Thread类
将Runnable对象转化为工作任务的传统方式就是把它提交给一个Thread构造器,如:
public class ThreadDemo {
public static void main(String[] args) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
System.out.println("---Thread---");
}
}
输出结果:
Thread构造器只需要一个Runnable对象。调用Thread对象的start()方法为该线程执行必需的初始化操作,然后调用Runnable的run()方法,以便在这个新线程中启动该任务。尽管start()方法看起来是产生了一个对长期运行方法的调用,但从输出中可以看到,“---Thread---”消息在倒计时完成之前就出现了,实际上,产生的是对Demo.run()的方法的调用,并且这个方法还没有完成,但是因为Demo.run()是由不同的线程执行的,因此仍旧可以执行main()线程中的其他操作,这种并不局限于main()线程,任何线程都可以启动另一个线程。因此,程序会同时运行两个方法,main()和Demo.run()是程序中与其它线程同时执行的代码。
当然,也可以添加更多的线程去驱动更多的任务,如下例子可以看到所有任务彼此之间是如何互相呼应的:
public class ManyDemo {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Demo demo = new Demo();
Thread thread = new Thread(demo);
thread.start();
System.out.println("---Thread---");
}
}
}
输出结果:
输出结果说明不同任务的执行在线程被换进换出时混在了一起。这种交换是由线程调度器自动控制的。这个例子一次运行的结果可能与另一次运行的结果不同,因为线程机制是非确定性的。