多线程
来源:互联网 发布:纹理过滤 三线性优化 编辑:程序博客网 时间:2024/05/19 03:28
Java中创建线程有两种方式:继承Thread重写run()与实现Runnable()接口通过Thread构造。
继承Thread重写run()
创建一个TestThread继承自Thread,然后调用start()运行线程
TestThread testThread = new TestThread();testThread.start(); public class TestThread extends Thread{ @Override public void run() { super.run(); Log.i("thread","TestThread"); } }
打印的log为:TestThread
I/thread: TestThread
实现Runnable接口
定义一个类TestRunnable实现Runnable的run方法,通过Thread的构造函数传入一个TestRunnable对象,调用start()开启线程
Thread runnable = new Thread(new TestRunnable()); runnable.start(); public class TestRunnable implements Runnable{ @Override public void run() { Log.i("thread","testRunnable"); } }
打印的log为:testRunnable
I/thread: testRunnable
继承Thread类与实现Runnable接口的原理和区别
通过上面的两种方式都可以实现多线程,那么将TestRunnable对象传给TestThread会是怎样的呢?代码走起
TestThread testThread = new TestThread(new TestRunnable()); testThread.start(); public class TestThread extends Thread{ public TestThread(Runnable target) { super(target); } @Override public void run() { super.run(); Log.i("thread","TestThread"); } } public class TestRunnable implements Runnable{ @Override public void run() { Log.i("thread","testRunnable"); } }
运行代码,发现log分别打印了TestThread和testRunnable
I/thread: TestThreadI/thread: testRunnable
而调用Thread的start()函数会创建一个新的线程以及调用线程的run()方法,而在TestThread的run()方法中,调用了super.run(),说明super.run()中调用了TestRunnable的run()方法,那看看Thread中构造函数传入Runnable对象是如何实现的。
public class Thread implements Runnable { public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) { /*省略其他的一些代码*/ this.target = target; setPriority(priority); tid = nextThreadID(); } @Override public void run() { if (target != null) { target.run(); } }}
可以发现Thread也是实现了Runnable接口,在构造函数时将传入的Runnable对象赋值给了target,而在实现的run()函数中调用了target.run(),即我们构造函数传入的Runnable对象。因此我们可以得到,通过继承Thread和实现Runnable本质是一样的,Thread是通过重写run()函数,而Runnable的方式间接通过Thread的target属性来调用run()函数,都依托于Thread,最终执行run()函数。
start()与run()的区别
通过上面的分析可以得知道Thread实现了Runnable接口,最终执行的也是run()函数,而我们在调用启动线程的时候是start()函数,那么他们有什么区别呢?首先看段代码
TestThread testThread = new TestThread();testThread.start(); try { Thread.sleep(200); } catch (InterruptedException ignored) { }Log.i("thread","TestThread start"); public class TestThread extends Thread{ @Override public void run() { super.run(); for (int i = 0; i < 10 ; i ++) { Log.i("thread","TestThread" + i); try { Thread.sleep(200); } catch (InterruptedException ignored) { } } } }
在TestThread的run()打印10行log,然后在调用start()打印TestThread start,sleep 200毫秒方便看打印顺序,看看打印的结果如何
thread: TestThread0thread: TestThread startthread: TestThread1thread: TestThread2thread: TestThread3thread: TestThread4thread: TestThread5thread: TestThread6thread: TestThread7thread: TestThread8thread: TestThread9
因为TestThread是多线程执行的,因此TestThread start打印在TestThread0之后是正常的,既然start()间接调用了run(),那么我们直接调用run()会怎样呢?
TestThread testThread = new TestThread(); testThread.run(); try { Thread.sleep(200); } catch (InterruptedException ignored) { } Log.i("thread","TestThread start");
输出的log如下
thread: TestThread0thread: TestThread1thread: TestThread2thread: TestThread3thread: TestThread4thread: TestThread5thread: TestThread6thread: TestThread7thread: TestThread8thread: TestThread9thread: TestThread start
发现TestThread是最后打印的,在执行完TestThread的run()方法之后才执行,变成了同步执行。
看看Thread的start()函数是怎么实现的
/** * Starts the new Thread of execution. The <code>run()</code> method of * the receiver will be called by the receiver Thread itself (and not the * Thread calling <code>start()</code>). * * @throws IllegalThreadStateException - if this thread has already started. * @see Thread#run */ public synchronized void start() { checkNotStarted(); hasBeenStarted = true; nativeCreate(this, stackSize, daemon); } private native static void nativeCreate(Thread t, long stackSize, boolean daemon);
在start()函数中调用了nativeCreate来创建一个线程,而start()的注释中也写明,创建一个新的线程,run()函数的代码在新的线程里面执行,而start()函数的线程在调用start()的线程里面执行。
根据上面的分析可以得到,直接调用run()函数没有创建新的线程,而是在调用的线程中执行,因此变成了同步执行;而调用start()函数,start()函数会在调用的线程中执行,还是属于同步执行,但是start()函数会创建一个新的线程来执行run()函数,因此我们通过继承Thread还是实现Runnable重写run()函数都会在新的线程执行,从而变成异步执行。
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- Red and Black
- electron + vue 实践项目
- 两粒种子,一片森林 jzoj 2017.8.22 B组
- HDMI之DDC通道
- 添加的依赖
- 多线程
- python: IO操作
- HDU 6170 Two strings
- 异步协程处理requests阻塞
- java提高篇(八)-----详解内部类
- lightoj 1011 Marriage Ceremonies (KM模板题)
- ReactNative-综合案例(01)
- 这个“打工二代”凭啥成了高层次人才
- HDU6165 FFF at Valentine【BFS】