一、进程与线程的区别:
一个进程可以包括多个线程,每个进程都需要操作系统为其分配独立的内存地址空间,同一进程的所有线程在同一块地址空间中工作。
二、JAVA线程的运行机制:
在JAVA虚拟机进程中,执行程序代码的任务是由线程完成的,每个线程都有一个独立的程序计数器和方法调用栈(method invocation stack)。程序计数器也称PC寄存器,当线程执行一个方法时,程序计数器指向方法区中的下一条要执行的字节码指令。方法调用栈是用来跟踪线程运行中一系列的方法调用过程,栈中的元素称为栈帧。每个线程调用一个方法的时候,就会向方法栈压入一个新帧,帧用来存储方法的参数、局部变量和运算过程中的临时数据。栈帧分为三部分:局部变量区、操作数栈和栈数据区。
当JAVA命令启动一个JAVA 虚拟机进程时,JAVA虚拟机都会创建一个主线程,该线程从程序的入口main()方法开始执行。线程的运行过程例子:
三、线程的创建和启动
创建线程有两种方式:(1)扩展java.lang.Thread类;(2)实现Runnable接口。
Thread类主要有两个方法:run()——包含线程运行时所执行的代码;start()——用于启动线程。
1、线程运行过程的例子:
2、主程序与用户自定义的线程并发运行的例子:
运行结果:
因为start方法是启动一个线程,覆盖的时候可能启动的是被覆盖的线程,而不是本身这个线程。假如一定要覆盖start()方法,那么应该先调用super.start()方法。下面例子的Machine类的start()方法首先调用Thread父类start()方法,确保Machine线程被启动,接着统计被启动的Machine线程的数目,并打印该数目。
一个类不能继承多个类,因此一旦一个类继承了Thread类就不能继承其他的类,为了解决这个问题,java提供了java.lang.Runnable接口,它有一个run()方法。
运行结果:
一个进程可以包括多个线程,每个进程都需要操作系统为其分配独立的内存地址空间,同一进程的所有线程在同一块地址空间中工作。
二、JAVA线程的运行机制:
在JAVA虚拟机进程中,执行程序代码的任务是由线程完成的,每个线程都有一个独立的程序计数器和方法调用栈(method invocation stack)。程序计数器也称PC寄存器,当线程执行一个方法时,程序计数器指向方法区中的下一条要执行的字节码指令。方法调用栈是用来跟踪线程运行中一系列的方法调用过程,栈中的元素称为栈帧。每个线程调用一个方法的时候,就会向方法栈压入一个新帧,帧用来存储方法的参数、局部变量和运算过程中的临时数据。栈帧分为三部分:局部变量区、操作数栈和栈数据区。
当JAVA命令启动一个JAVA 虚拟机进程时,JAVA虚拟机都会创建一个主线程,该线程从程序的入口main()方法开始执行。线程的运行过程例子:
public class Sample
{
private int a;//实例变量
public int method()
{
int b=0;//局部变量
a++;
b=a;
return b;
}
public static void main(String args[])
{
Sample s=null;//局部变量
int a=0;//局部变量
s=new Sample;
a=s.method;
System.out.println(a);
}
}
程序从main()入口,当它执行到method()方法的a++操作时,主程序能根据method()方法的栈帧的栈数据区中的有关信息,正确地定位到堆区的Sample对象的实例变量a,并把它的值加1。当meithod()方法执行完毕后,它的栈帧就会从方法栈中弹出,它的局部变量b结束生命周期。main()方法的栈帧就会成为当前帧,主线程继续执行main()方法。
三、线程的创建和启动
创建线程有两种方式:(1)扩展java.lang.Thread类;(2)实现Runnable接口。
Thread类主要有两个方法:run()——包含线程运行时所执行的代码;start()——用于启动线程。
1、线程运行过程的例子:
package extendth;
public viod Machine extends Thread
{
public void run()//下面大括号里面的两行代码是machine进程时执行的代码
{
for(int a=0;a<50;a++)
System.out.println(a);
}
public static void main(String args[])
{
Machine machie=new Machine();
machie.start();//启动machine进程
}
}
当运行java extendth.Machine命令时,java虚拟机首先创建并启动主线程,执行main()方法,main()方法创建一个Machine对象,然后调用它的start()方法启动Machine进程。Machine线程的任务是执行它的run()方法。2、主程序与用户自定义的线程并发运行的例子:
package allrun;
public class Machine extends Thread
{
public void run()
{
for(int a=0;a<50;a++)
{
System.out.println(currentThread().getName()+":"+a);
try
{
sleep(100);//给其他线程运行的机会
}catch(InterruptedException e)
{
throw new RuntimeException(e);
}
}
}
public static void main(String args[])
{
Machine machine1 = new Machine();//创建第一个Machine对象
Machine machine2 = new Machine();//创建第二个Machine对象
machine1.start();//启动第一个Machine线程
machine2.start();//启动第二个Machine线程
machine1.run();//主程序执行第一个Machine对象的run()方法
}
}
上面的例子Machine类的main()方法创建并启动了两个Machine线程,main()方法接着调用第一个Machine对象的run方法。在java虚拟机中有三个线程并发执行的Machine对象的run()方法。在三个线程中各自的方法栈都有代表run()方法的栈帧,在这个帧中存放了局部变量a,可见每个线程都有自己的局部变量a,他们都分别从0增加到50。运行结果:
main:0
Thread-0:0
Thread-1:0
main:1
Thread-0:1
Thread-1:1
……
main:49
Thread-0:49
Thread-1:49
3、多个线程共享一个对象的实例变量 package sharever;
public class Machine extends Thread
{
private int a=0;//实例变量
public void run()
{
for(int a=0;a<50;a++)//使用Machine对象的实例变量a
{
System.out.println(currentThread().getName()+":"+a);
try
{
sleep(100);
}catch(InterruptedException e)
{
throw new RuntimeException(e);
}
}
}
public static void main(String args[])
{
Machine machine=new Machine;
machine.start();
machine.run()
}
}
运行以上程序,主线程和Machine线程都会执行Machine对象的run()方法,都会操纵同一个实例变量a,这两个线程轮流给变量a增加1。运行结果:
main:0
Thread-0:0
main:1
Thread-0:2
……
main:48
Thread-0:49
4、不要随便覆盖Thread类的start()方法因为start方法是启动一个线程,覆盖的时候可能启动的是被覆盖的线程,而不是本身这个线程。假如一定要覆盖start()方法,那么应该先调用super.start()方法。下面例子的Machine类的start()方法首先调用Thread父类start()方法,确保Machine线程被启动,接着统计被启动的Machine线程的数目,并打印该数目。
package correctstart;
public class Machine extends Thread
{
private int a=0;
private static int count=0;//统计被启动的Machine线程的数目
public void start()
{
super.start();
System.out.println(currentThread().getName()+":第"+(++count)+"个Machine进程启动");//这行代码由主线程执行
}
public void run()
{
for(int a=0;a<50;a++)//使用Machine对象的实例变量a
{
System.out.println(currentThread().getName()+":"+a);
try
{
sleep(100);
}catch(InterruptedException e)
{
throw new RuntimeException(e);
}
}
}
public static void main(String args[])
{
Machine machine=new Machine;
machine.start();
machine.run()
}
}
public static void main(String args[])
{
Machine machine1 = new Machine();
Machine machine2 = new Machine();
machine1.start();
machine2.start();
machine1.run();
}
}
5、实现Runnable接口一个类不能继承多个类,因此一旦一个类继承了Thread类就不能继承其他的类,为了解决这个问题,java提供了java.lang.Runnable接口,它有一个run()方法。
package runimpl;
public class Machine implements Runnable
{
private int a=0;
public void run()
{
for(int a=0;a<50;a++)
{
System.out.println(currentThread().getName()+":"+a);
try
{
sleep(100);
}catch(InterruptedException e)
{
throw new RuntimeException(e);
}
}
}
public static void main(String args[])
{
Machine machine=new Machine();
Thread t1=new Thread(machine);
Thread t2=new Thread(machine);
t1.start();
t2.start()
}
}
在这个例子中,主线程创建了t1和t2两个线程对象,启动t1和t2线程将执行machine变量所引起的Machine对象的run()方法。t1和t2共享同一个machine对象,因此在执行run()方法时将操纵同一个实例变量a。运行结果:
Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:2
……
Thread-0:47
Thread-1:48
Thread-0:49
将以上的main()方法做如下修改,t1和t2线程分别执行machine1和machine2变量所引起的Machine对象的run()方法,因此操纵的是不同的变量a。
public static void main(String args[])
{
Machine machine1=new Machine();
Machine machine2=new Machine();
Thread t1=new Thread(machine);
Thread t2=new Thread(machine);
t1.start();
t2.start()
}
运行结果:
Thread-0:0
Thread-1:0
……
Thread-0:49
Thread-1:49
一个不错的线程启动与停止方式:
public class MyThread implements Runnable{
private boolean flag=true;
public void run() {
while (flag) {…
}
}
public void stopRunning(){
flag=false;
}
}
public class ControlThread{
private Runnable r=new MyThread();
private Thread t=new Thread(r);
public void startThread() {
t.start();
}
public void stopThread() {
r.stopRunning();
}
}
转载自:http://blog.sina.com.cn/s/blog_4bea2fb101000bom.html
参考:
Java多线程(一)、多线程的基本概念和使用:http://blog.csdn.net/lonelyroamer/article/details/7948329
并发编程网:http://ifeve.com/creating-and-starting-java-threads/
Java线程:创建与启动:http://lavasoft.blog.51cto.com/62575/99151
进程与线程:http://blog.csdn.net/kaoa000/article/details/8491054
总结:
Start和Run的区别:
如果程序从未调用线程对象的start方法来启动它,那么这个线程对象将一直处于“新建状态”,它永远也不会作为线程获得执行的机会,它只是一个普通的Java对象。当线程调用线程对象的run方法时,与调用普通的Java对象并没有任何区别,因此绝对不会启动一个新线程。