1 线程就绪、运行和死亡状态转换
- 就绪状态转换为运行状态:此线程得到CPU资源;
- 运行状态转换为就绪状态:此线程主动调用yield()方法或在运行过程中失去CPU资源。
- 运行状态转换为死亡状态:此线程执行执行完毕或者发生了异常;
注意:
当调用线程中的yield()方法时,线程从运行状态转换为就绪状态,但接下来CPU调度就绪状态中的那个线程具有一定的随机性,因此,可能会出现A线程调用了yield()方法后,接下来CPU仍然调度了A线程的情况。
2 run & start
通过调用start启动线程,线程执行时会执行run方法中的代码。
- start():线程的启动;
- run():线程的执行体;
3 sleep & yield
sleep():通过sleep(millis)使线程进入休眠一段时间,该方法在指定的时间内无法被唤醒,同时也不会释放对象锁;
比如,我们想要使主线程每休眠100毫秒,然后再打印出数字:
/**
* 可以明显看到打印的数字在时间上有些许的间隔
*/
public class Test1 {
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<100;i++){
System.out.println("main"+i);
Thread.sleep(100);
}
}
}
注意如下几点问题:
- sleep是静态方法,最好不要用Thread的实例对象调用它,因为它睡眠的始终是当前正在运行的线程,而不是调用它的线程对象,它只对正在运行状态的线程对象有效。看下面的例子:
```java
public class Test1 {
public static void main(String[] args) throws InterruptedException {
}System.out.println(Thread.currentThread().getName());
MyThread myThread=new MyThread();
myThread.start();
// 这里sleep的就是main线程,而非myThread线程
myThread.sleep(1000);
Thread.sleep(10);
for(int i=0;i<100;i++){
System.out.println("main"+i);
}
}
2. Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。但是不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而不能做到精准控制。**因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它**,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒。
```java
public class Test1 {
public static void main(String[] args) throws InterruptedException {
new MyThread().start();
new MyThread().start();
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(this.getName()+"线程" + i + "次执行!");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
看某一次的运行结果:可以发现,线程0首先执行,然后线程1执行一次,又了执行一次。发现并不是按照sleep的顺序执行的。
Thread-0线程0次执行!
Thread-1线程0次执行!
Thread-1线程1次执行!
Thread-0线程1次执行!
Thread-0线程2次执行!
Thread-1线程2次执行!