写在前头:近期或多或少的去了一些比较优秀的企业面试,现在的企业要求比较高,当然也可能和你面试的岗位有关,一定的工作年限需要有对应的知识的深度和宽度,并且会发现一个特性,就是面试官非常注重你的基础知识的理解和掌握能力,比如说去面试Android开发,但是可能会问你很多的java知识,包括Http和Https,还有网络通信,H5数据交互等等知识点,那么我们应该如何应对这些呢,答案只有一个,多看多理解多积累,毕竟咱们这一行速成容易,精通很难,所以这就是为什么实际工作过的攻城狮和培训出来的人最直接的区别,一个是精通原理,一个是掌握使用方法,在现在这个阶段,优秀的企业挑选的只会是掌握原理的人,哪怕不会用到,但是这代表了一个攻城狮的自我修养,自己的学习能力,自己的钻研能力,好了,写到这儿,我会写一系列的面试知识点整理,也就是我遇到的一些比较有意思的东西,和大家分享,开始吧!
相信Thread对我们来说并不陌生,学java的时候都是入门的东西,我们一般使用thread都是new一个线程,然后调用start方法启动,使用start方法才真正实现了多线程运行,因为这个时候不用等待我们的run方法执行完成就可以继续执行下面的代码,这才叫多线程嘛!因为thread线程有5种状态,创建-就绪-运行-阻塞-死亡这五种,那么我们的start方法呢就是就绪这一步,因为这个时候我们的线程并没有立即的执行,而是得等待,等到我们的cpu有空闲的时候,才会执行线程里面的run方法,等run方法执行完了,线程就结束了。
那么我们直接使用thread执行run方法会咋样呢?因为run方法是thread里面的一个普通的方法,所以我们直接调用run方法,这个时候它是会运行在我们的主线程中的,因为这个时候我们的程序中只有主线程一个线程,所以如果有两个线程,都是直接调用的run方法,那么他们的执行顺序一定是顺序执行,所以这样并没有做到多线程的这种目的。
下面来写一段简单的代码,运行一下看看效果,加深大家的印象。
public class ThreadDemo {
public static void main(String[] args){
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(i);
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
根据我们上面的分析,这两个线程都是使用start方法开启的,所以并不需要等待另一个完成,所以他们的执行顺序应该是并行的,我们运行看一下结果:
和我们分析的一样,那么我们改改代码,执行使用run方法,看看是否顺序执行
public static void main(String[] args){
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.run();
thread2.run();
}
其实这也很容易理解对不对,直接使用对象调用方法,那必须是这个方法执行完了代码才能往下走啊,嗯,没毛病!
深入一点,我们来看看源码是怎么干的吧!
首先看看run方法是如何做的,点击run方法会跳进Thread.java源码中:
@Override
public void run() {
if (target != null) {
target.run();
}
}
好理解吧?target不为空,就执行run方法,target是啥?
/* What will be run. */
private Runnable target;
可以看到target就是我们的Runnable 对象本身,所以能理解吧,没毛病哈?
下面来看看start方法如何干的!
public synchronized void start() {
//这里private volatile int threadStatus = 0;初始化的时候就是0
//如果这里不为0的话就抛异常
if (threadStatus != 0)
throw new IllegalThreadStateException();
//把当前线程加入到线程组中
//private ThreadGroup group;就是这么个东西
group.add(this);
//初始化标记位未启动
boolean started = false;
try {
start0();
//标识为启动状态
started = true;
} finally {
try {
//如果没开启,标识为启动失败
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
注意这里有个start0()方法,源码是
private native void start0();
这里用到了native修饰符,表示调用本机的操作系统函数,也可能是VM的,这是因为多线程需要我们机器底层的支持,比如说cpu啥的。
好了,到这儿应该都能理解了,我就不写总结了,毕竟这一篇都像是个总结,那我们下回再见见别的~