鱼儿眼中的海

业精于勤荒于嬉,行成于思毁于随.

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Java虚拟机的主线程,它从启动类main()方法开始运行。用户也可以创建自己的线程,它将和主线程并发运行。创建线程的两种方式:

  (1)继承java.lang.Thread类;

  (2)实现Runnable接口。

 1.扩展java.lang.Thread类,用户的线程只需要继承Thread类,覆盖Thread类的run()方法即可。

 实例:run()方法指定这个线程所执行的代码。

public class Machine extends Thread {
    //重写Thread类的run()方法
    public void run(){
        for(int a=0;a<50;a++){
            System.out.println(currentThread().getName()+":"+a);
        }
        try {
            sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Machine m=new Machine();    //创建第一个machine对象
        Machine m1=new Machine();   //创建第二个machine对象
        m.start();            //启动第一个machine线程,因为Machine类继承Thread类,重写了run()方法
        m1.start();            //启动第二个machine线程
     m.run();              //主线程执行第一个Machine对象的run()方法 } }

   1.1  上面,主线程执行main()方法时,会创建两个Machine对象,然后启动两个Machine线程。接着主线程开始执行第一个Machine对象的run()方法。在Java虚拟机中有三个线程并发执行Machine对象的run()方法。三个线程各自的方法栈中都有代表run()方法的栈帧,在这个帧中存放局部变量a,可见(3)每个线程都拥有自己的局部变量a,它们都从0增加到50。

   run()方法中currentThread().getName()相当于:

Thread thread=new Thread(); //返回当前正在执行这行代码的线程的引用
String name=thread.getName();  //获得线程的名字

 

  线程默认为Thread-0  Thread-1可以通过Thread类的setName()方法显式设置线程的名字。

  1.2 多个线程共享同一个对象的实例变量

public class Machine extends Thread{
    private int a;
    public void run(){
        for(a=0;a<50;a++){
            System.out.println(currentThread().getName()+":"+a);
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Machine m=new Machine();
        m.start();
        m.run();
    }
}

    上面代码,主线程和Machine线程都会执行Machine对象的run()方法:主线程和Machine线程并发执行Machine对象的run()方法时,都会操纵同一个实例变量a,这两个线程轮流给变量a增加1.

public class TestOne extends Thread{
    private int a;
    //重写Thread类的run()方法
    public void run(){
        for(a=0;a<30;a++){
            System.out.println(currentThread().getName()+":"+a);        
        }
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        TestOne t1=new TestOne();
        TestOne t2=new TestOne();
        t1.start();
        t2.start();
    }
}

   以上代码,因为实例方法和静态方法的字节码都位于方法区,被所有线程共享。t1线程和t2线程分别执行t1对象和t2对象的run()方法,意味着t1执行run()方法时,会把run()方法中的变量a解析为t1对象的实例变量a,t2线程执行run()方法时,会把run()方法中的变量a解析为t2对象的实例变量a。所以,t1线程和t2线程分别操纵不同的实例变量a。各自输出0-29

 1.3 不要随便覆盖Thread类的start()方法

  随意覆盖,所有方法的调用都会变成主线程完成。假如一定要覆盖start()方法,那么应该先调用super.start()方法。

1.4 一个线程只能被启动一次

public static void main(String[] args) {
        TestOne t1=new TestOne();
        TestOne t2=t1;
        t1.start();
        t2.start();
}

 

 

 

  如果将上面代码main部分改成这样,t2.start()会抛出java.lang.IllegalThreadStateException异常。

 

2.实现Runnable接口

public class Machine implements Runnable{
  privat int i=0; @Override
public void run() { for(i=0;i<40;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { Machine m=new Machine(); Thread t1=new Thread(m); Thread t2=new Thread(m); t1.start(); t2.start(); } }

 

 

 

  如上,主线程创建了t1和t2两个线程对象。启动t1和t2线程将执行m变量所引用的Machine对象的run()方法。t1和t2共享同一个machine对象。因此执行run()方法时将操纵同一个实例变量i.

 

posted on 2016-04-13 11:07  鱼儿眼中的海  阅读(137)  评论(0编辑  收藏  举报