创建线程的方法
来源:互联网 发布:输入网络凭据是什么 编辑:程序博客网 时间:2024/06/11 16:19
从操作系统的角度来看,线程是CPU调度的最小单位——可以理解为一种资源、权利,即能够获得CPU的使用权
网上很多文章中说java创建线程的方法有两种(Thread Runnable)或三种(外加Callable Future),这种说法不能说是错误的,但是很容易误导人,实际上,创建线程(拥有CPU使用权的线程)只有一种方法,那就是继承Thread类。实现Runnable(包括Callable Future)准确地说,不是线程,而是任务,站在操作系统的角度来看,一个类实现类Runnable,并没有立刻获得能够使用CPU的权利,来看一下Runnable和Thread的源码
@FunctionalInterfacepublic interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * * @see java.lang.Thread#run() */ public abstract void run();}
public class Thread implements Runnable { private ThreadGroup group; public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } private native void start0(); /** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * @see #start() */ @Override public void run() { if (target != null) { target.run(); } }
注释我去掉了一些,从Thread.run()方法来看,Runnable要是能运行的话——获得CPU的使用权,那么要放在Thread的构造函数中,否则不执行,然后看Thread.start()方法,其中调用了start0()方法,该方法是个本地方法,本地方法的实现要去看源码,openjdk8的源码下载地址,因为最终是要看cpp的,而我不会cpp,引用另外两篇博文:调用Thread.start()方法,JVM(Hotspot)会调用操作系统的API来创建一个操作系统线程,此时一个Java线程对象就与一个操作系统线程一一对应。
那么为什么需要Runnable接口呢?只有Thread不就够类么,重写run()方法就行了,网上很多都说Runnable是接口,而Thread是类,实现Runnable能够避免Java单根继承带来的局限,且实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享
我认为都没说到点子上,重点是:调用Thread.start()时,是通过操作系统来创建线程的,而创建线程必然是运行在内核态,那么就一定有上下文切换,从而带来额外的时间和空间开销。如果将线程(Thread对象)看作插槽,它代表了资源——能够使用CPU(其实还有寄存器等存储资源),Runnable对象看作插头——要运行的任务,因为创建、撤销插槽开销很大,那么可以先创建一组插槽,什么任务需要运行,就插入相应的插头,就能够避免频繁的创建、撤销,避免上下文切换,从而提高性能,没错,就是线程池的思想
很多地方的线程和任务并没有分清楚,比如这里,若是站在java程序员的角度,Runnable就是一个线程,为啥?我要在执行多个任务,实现Runnable接口,不就是线程么
1.1实现Runnable接口
public class MyRunnable{ public static void main(String[] args) { Thread[] ths = new Thread[3]; for (int i = 0; i < 3; i++) { ths[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < 5; j++) System.out.print(j); System.out.print(" "); } }); } for (Thread th: ths) th.start(); }}
注意Runnable使用了匿名内部类,
1.2继承自Thread类
public class MyThread extends Thread{ @Override public void run(){ for (int i = 0; i < 5; i++) System.out.print(i); System.out.print(" "); } public static void main(String[] args){ MyThread[] thx = { new MyThread(), new MyThread(), new MyThread(), }; for (MyThread th: thx){ th.start(); } }}
需要注意的是,以上两个程序中,线程的启动顺序是确定的,但是执行顺序是不确定的,因为是并发执行而不是顺序执行的,JVM和操作系统一起决定了线程的执行顺序,下图分别为Runnable在windown7+jdk1.7.0_67和ubuntu16.04+jdk1.8.0_101上运行的结果
参考资料:
1. java编程思想
2. http://www.ticmy.com/?p=230
3. http://blog.csdn.net/jeffhtlee/article/details/12751825
- 线程的创建方法
- 创建线程的方法
- 创建线程的方法
- 创建线程的方法
- 线程的创建、线程的基本方法、
- Java 线程的创建方法
- 创建一个线程的方法
- 创建线程的方法2
- Java 创建线程的方法
- 创建线程的方法二
- vc 创建线程的方法
- java 线程创建的方法
- 创建线程函数的方法
- Java线程的创建方法
- 创建线程类的方法
- Java 创建线程的方法
- 创建线程的一种方法
- 线程的两个创建方法
- Timus Online Judge:1119. Metro
- Android Studio(DDMS)中的那些招
- C#连接MySQL数据库
- 2.2 SimpleAdapter的使用
- linux-ln -s(链接)、mount(挂载)
- 创建线程的方法
- Quartz.net开源作业调度框架使用详解
- zynq的三种启动方式(JTAG,SD,QSPI)
- jsp的9大内置对象
- form表单中method的get和post区别
- 启动apache时报错libmysqlclient.so.16 not found的处理
- webpack的学习
- Spark优化一则 - 减少Shuffle
- Ubuntu 安装Navicat,界面出现乱码解决方法