java基础---->多线程之Runnable(一)

  java线程的创建有两种方式,这里我们通过简单的实例来学习一下。一切都明明白白,但我们仍匆匆错过,因为你相信命运,因为我怀疑生活。

java中多线程的创建

一、通过继承Thread类来创建多线程

public class HelloThread extends Thread {
    @Override
    public void run() {
        try {
            TimeUnit.SECONDS.sleep(1);
            System.out.println("Hello from a thread!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        HelloThread helloThread = new HelloThread();
        helloThread.start();
        System.out.println("In main thread.");
    }
}

运行的结果如下:

In main thread.
Hello from a thread!

我们这里对Thread类的start的方法做一些说明,官方文档的说明:

Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread. 
The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method). 
It is never legal(合法) to start a thread more than once(不止一次). In particular, a thread may not be restarted once it has completed execution. 

Throws: 
    IllegalThreadStateException - if the thread was already started

我们在上述例子的基础上,对上述的说明做一个代码的测试。在helloThread.start();代码的后面添加代码:

System.out.println(helloThread.getName());
helloThread.start();

一次的运行结果如下所示,在添加代码的第二行(helloThread.start();)报的错误。

Exception in thread "main" java.lang.IllegalThreadStateException
Thread-0
    at java.lang.Thread.start(Thread.java:708)
    at com.linux.huhx.thread.HelloThread.main(HelloThread.java:22)
Hello from a thread!

如果在添加helloThread.start();之前让主线程睡眠3秒,也就是让先启动的helloThread线程执行完毕。我们再调用helloThread.start()启动线程。

TimeUnit.SECONDS.sleep(3);
System.out.println(helloThread.getName());
helloThread.start();

运行的结果如下:

Hello from a thread!
Thread-0
Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:708)
    at com.linux.huhx.thread.HelloThread.main(HelloThread.java:22)

二、通过实现Runnable接口来创建多线程

public class HelloRunnable implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("Hello from a thread!");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new HelloRunnable());
        thread.start();
        System.out.println("In main method.");
    }
}

运行的结果如下:

In main method.
Hello from a thread!

  这种使用实现HelloRunnable接口的方式是比较推崇的,因为java类中只能单继承可以多实现。现在看一下它的简单原理new Thread(new HelloRunnable())的源码如下:

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

init的方法是初始化线程的一些信息:

private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;

    Thread parent = currentThread();
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
        if (security != null) {
            g = security.getThreadGroup();
        }

        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

    g.checkAccess();

    if (security != null) {
        if (isCCLOverridden(getClass())) {
            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
    }

    g.addUnstarted();

    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;
    this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
    this.target = target;
    setPriority(priority);
    if (inheritThreadLocals && parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    this.stackSize = stackSize;
    tid = nextThreadID();
}

  最重要的一行代码就是this.target = target;设置了线程target为我们的Runnable对象。我们都知道thread.start()启动一个线程,实际是调用线程的run方法。现在我们看一下Thread类的run方法。

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

  可以看到是调用了target的run方法,在我们这里就是(HelloRunnable)。对于继承Thread的的情况来说,就拿上述的HelloThread来讲,它里面的target是空的。不过执行的run方法是HelloThread重写的run方法。所以不存在HelloThread中没有target就不会执行的情况。

友情链接

原文地址:https://www.cnblogs.com/huhx/p/baseusejavathreadrunnable.html