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.IllegalThreadStateExceptionThread-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-0Exception 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方法。
@Overridepublic void run() { if (target != null) { target.run(); }}
可以看到是调用了target的run方法,在我们这里就是(HelloRunnable)。对于继承Thread的的情况来说,就拿上述的HelloThread来讲,它里面的target是空的。不过执行的run方法是HelloThread重写的run方法。所以不存在HelloThread中没有target就不会执行的情况。
友情链接