多线程

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。

1.继续Thread类

T.java
/**
 * User: liuwentao
 * Date: 2011-5-5 18:36:31
 * <p/>
 * 说明:
 */
public class T extends Thread {

    public T() {
    }

    public T(String threadName) {
        super(threadName);
    }

    public void run() {
        String threadName = super.getName();
        System.out.println(threadName + " 线程运行开始!");
        for (int i = 0; i < 5; i++) {
            double sleepTime = Math.random() * 10;
            System.out.println(i + " " + threadName + ",sleepTime=" + sleepTime);
            try {
                sleep((int)sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(threadName + " 线程运行结束!");
    }
}

TestT.java
/**
 * User: liuwentao
 * Date: 2011-5-5 18:37:01
 * <p/>
 * 说明:
 */
public class TestT {

    /**
     * main方法其实也是一个线程
     * @param rags
     */
    public static void main(String[] rags) {
        Thread currentThread = Thread.currentThread();
        String currentThreadName = currentThread.getName();
        System.out.println("******" + currentThreadName + " 线程运行开始!");

        T t1 = new T("Thread-A");
        //如果我们没有指定名字的话,系统自动提供名字。如:Thread-0
        T t2 = new T();

        t1.start();
        t2.start();

        System.out.println("******" + currentThreadName + " 线程运行结束!");
    }
}

执行结果

多线程_第1张图片

主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。

注意:

1:启动线程一定是 start()方法,而不是run()方法,如果写成run()方法启动
        t1.run();
        t2.run();

执行结果:

多线程_第2张图片

就全变成 顺序执行的了。这是不对的。

为什么我们不能直接调用run()方法呢?因为线程的运行需要本地操作系统的支持。 如果查看start的源代码的时候,会发现:
public synchronized void start() {
        if (threadStatus != 0 || this != me)
            throw new IllegalThreadStateException();
        group.add(this);
	//这个方法有native关键字
        start0();
        if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
}

/**
* native关键字表示调用本地操作系统的函数。
* 因为多线程的实现需要本地操作系统的支持。
*/
private native void start0();


2:start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。

如写成这样:
        t1.start();
        t2.start();
        t1.start();

执行结果:

多线程_第3张图片
可以看到程序抛出了异常,
引用
******main 线程运行结束!

这句话不会出现

2.实现Runnable接口

R.java
/**
 * User: liuwentao
 * Date: 2011-5-5 18:36:31
 * <p/>
 * 说明:
 */
public class R implements Runnable {
    private String name;

    public R() {
    }

    public R(String threadName) {
        this.name = threadName;
    }

    public void run() {
        System.out.println(name + " 线程运行开始!");
        for (int i = 0; i < 5; i++) {
            int j = 0;
            while (j < 1000000) {
                j++;
            }
            System.out.println(i + " " + name);
        }
        System.out.println(name + " 线程运行结束!");
    }
}

TestR.java
/**
 * User: liuwentao
 * Date: 2011-5-5 18:37:01
 * <p/>
 * 说明:
 */
public class TestR {
    public static void main(String[] rags) {
        System.out.println(Thread.currentThread().getName() + " 线程运行开始!");

        R r1 = new R("A");
        R r2 = new R("B");

        Thread thread1 = new Thread(r1);
        thread1.start();
        Thread thread2 = new Thread(r2);
        thread2.start();

        System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
    }
}

执行结果:

多线程_第4张图片

其实Thread也是实现Runnable接口的:

多线程_第5张图片

Thread和Runnable的区别:

1:实现Runnable接口的多线程程序要通过 类似下面方式启动
        R r1 = new R("A");
        Thread thread1 = new Thread(r1);
        thread1.start();


而继承Thread类的多线程程序,则可以直接调用start()方法启动:
        T t1 = new T("Thread-A");
        t1.start();


2:Thread类中有一些方法,是Runnable接口中没有的,比如:
引用
sleep
yield
stop



2:如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
/**
 * 继承Thread类,不能资源共享
 * */
class hello extends Thread {
    private int count = 5;

    public void run() {
        for (int i = 0; i < 7; i++) {
            if (count > 0) {
                System.out.println("count= " + count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello h1 = new hello();
        hello h2 = new hello();
        hello h3 = new hello();
        h1.start();
        h2.start();
        h3.start();
    }
 
}

执行结果
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1

可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。
换为Runnable接口:
/**
 * 实现Runnable接口,能资源共享
 * */
class hello implements Runnable {
    private int count = 5;

    public void run() {
        for (int i = 0; i < 7; i++) {
            if (count > 0) {
                System.out.println("count= " + count--);
            }
        }
    }
 
    public static void main(String[] args) {
        hello he=new hello();
        new Thread(he).start();
    }
}

执行结果
count= 5
count= 4
count= 3
count= 2
count= 1


总结一下:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
所以建议大家劲量实现接口。

在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。

你可能感兴趣的:(多线程)