java 线程的创建与启动

一、进程与线程的区别:
一个进程可以包括多个线程,每个进程都需要操作系统为其分配独立的内存地址空间,同一进程的所有线程在同一块地址空间中工作。

二、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对象并没有任何区别,因此绝对不会启动一个新线程。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值