记一次失败的学习方式
线程的三中创建方式,先上代码:
/*
创建新线程的三种方式:
1、继承Thread类;
2、实现Runable接口;
3、匿名内部类;
需求:创建多线程对象,开启多线程。在子线程中输出1-100之间的偶数,主线程输出1-100之间的奇数。
*/
public class Test9 {
public static void main(String[] args) {
/*
线程启动必须调用start()方法,而非run()
//方式一
ThreadTest1 tt1 = new ThreadTest1();
tt1.setPriority(10);//设置线程优先级,默认为5,范围1-10
tt1.start();
*/
/*
//方式二
ThreadTest2 tt2 = new ThreadTest2();
Thread theTt2Thread = new Thread(tt2);
theTt2Thread.start();
*/
//方式三
Thread tt3 = new Thread(){
@Override
public void run(){
//使用匿名类可以很方便的访问外部变量(这里并未访问外部局部变量)
//但是在JDK7以前,就必须使用final修饰
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) System.out.println("子线程:" + i);
}
}
};
//tt3.setPriority(10);//线程优先级太高导致子线程打印完主线程才打印┓(?′?`?)┏233333(主线程默认5)
tt3.start();
//同时,该匿名类可以使用lambda表达式简化
Thread tt4 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) System.out.println("子线程:" + i);
}
});
//主线程打印奇数
for (int i = 0; i < 100; i++) {
if (i % 2 == 1) System.out.println("主线程:" + i);
}
}
}
//通过继承Thread类来创建新线程
class ThreadTest1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) System.out.println("子线程:" + i);
}
}
}
//通过实现Runnable接口来创建新线程
class ThreadTest2 implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) System.out.println("子线程:" + i);
}
}
}
最开始执行该代码时,会产生这样的结果:
子线程居然在主线程打印完了才开始打印,这曾一度让我以为没有创建出新线程,刚开始的时候start()方法在主方法下,我以为是顺序的原因,所以我先调用子线程的start()方法,然后在主方法打印(也就是现在的代码),发现结果还是这样,我甚至以为是因为ThreadTest方法不是公共的原因,然后想到之前看C#的时候有讲到优先级问题,然后百度了一下发现了具体原因:
结果居然变了
子线程居然又开始工作了,我花了一晚上查线程优先级问题,最后发现最开始的情况居然复现不了了???(绝对不是主线程for循环在上面的原因)
不行我得把我查到的结论整理一下o(╥﹏╥)o,等以后再遇到这种情况再说吧
线程的状态,这里有一个很经典的线程状态图:
新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
参见这篇博客
1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止、退出或者由于某些原因不执行的时候,低优先级的线程才可能被执行
2.两个优先级相同的线程同时等待执行时,那么运行系统会以round-robin的方式选择一个线程执行(即轮询调度,以该算法所定的)(Java的优先级策略是抢占式调度!)
3.被选中的线程可因为一下原因退出,而给其他线程执行的机会:
1) 一个更高优先级的线程处于可运行状态(Runnable)
2)线程主动退出(yield),或它的run方法结束
3)在支持分时方式的系统上,分配给该线程的时间片结束
4.Java运行系统的线程调度算法是抢占式(preemptive)的,当更高优先级的线程出现并处于Runnable状态时,运行系统将选择高优先级的线程执行
5.例外地,当高优先级的线程处于阻塞状态且CPU处于空闲时,低优先级的线程也会被调度执行参见这里
最后放个很详细的博客,不过有些地方还不是特别明白,以后再仔细研读
原文:https://www.cnblogs.com/lixin-link/p/10991710.html