多线程程序的引入图解
1 package cn.itcast_01; 2 /* 3 * 进程: 4 * 正在运行的程序,是系统进行资源分配和调用的独立单位。 5 * 每一个进程都有它自己的内存空间和系统资源。 6 * 线程: 7 * 是进程中的单个顺序控制流,是一条执行路径。 8 * 是程序的执行单元,执行路径。是程序使用CPU的最基本单位。 9 * 10 * 一个进程如果只有一条执行路径,则称为单线程程序。 11 * 一个进程如果有多条执行路径,则称为多线程程序。 12 * 13 * 举例: 14 * 扫雷程序,迅雷下载 15 * 16 * 大家注意两个词汇的区别:并行和并发。 17 * 并行:前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。 18 * 并发:后者是物理上同时发生,指在某一个时间点同时运行多个程序。 19 * 20 * 21 * 22 * Java程序的运行原理: 23 * 通过java命令会启动 java虚拟机。启动 JVM,等于启动了一个应用程序,也就是启动了一个进程。 24 * 该进程会自动启动一个 “主线程”,然后主线程去调用某个类的 main方法。所以 main方法运行在主线程中。在此之前的所有程序都是单线程的。 25 * 26 * 思考题: 27 * jvm虚拟机的启动是单线程的还是多线程的? 28 * 多线程的。 29 * 原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。 30 * 现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。 31 */ 32 public class MyThreadDemo { 33 public static void main(String[] args) { 34 System.out.println("hello"); 35 new Object(); // 造对象 36 new Object(); // 造对象 37 new Object(); // 造对象 38 new Object(); // 造对象 39 //...造很多很多对象后,如果垃圾回收线程不启动的话,内存就会溢出! 40 System.out.println("world"); 41 } 42 }
注意事项:
1:Thread类的方法:
public final String getName() 获取线程对象的名称(一般放在需要被线程执行的代run()方法里面)
public final void setName(String name) 设置线程对象的名称
对象名.setName("林青霞");
2:在不是Thread类的子类中,如何获取线程对象的名称呢?
public static Thread currentThread() 返回当前正在执行的线程对象(静态方法)
Thread.currentThread().getName()
3:该自定义的类为什么要重写run()方法?
自定义类中不是所有的代码都需要被线程执行。
而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()方法,用来包含那些需要被线程执行的代码。
注意:这里的 被线程执行 = 开一个新线程执行
4:由于自定义类实现了接口,所以就不能在自定义类中直接使用Thread类的getName()方法了,但是可以间接的使用。
Thread.currentThread().getName()
小问题:
1:为什么要重写run()方法?
答:run()方法里面封装的是被线程执行的代码。
2:启动线程对象用的是哪个方法?
答:start()方法
3:run()方法和start()方法的区别?
答:run()方法直接调用仅仅是普通方法。
start()方法是先启动线程,再由jvm去调用run()方法。
4:有了方式1,为什么还来一个方式2呢?
答:若自定义类MyThread类已经有一个父类了,那么它就不可以再去继承Thread类了。(java不支持多继承)
若自定义类MyRunnable类已经实现了一个接口了,那么它还可以再去实现Runnable接口。(java支持多实现)
即可以避免由于Java单继承带来的局限性。
在测试类MyThreadTest中,要想开多个线程,就要先new多个自定义类MyThread的对象,每一个自定义类MyThread的对象的成员变量都相同,这样需要在栈中开辟很多内存;
在测试类MyRunnableTest中,要想开多个线程,只需要new一个自定义类MyRunnable的对象,再new多个Thread类的对象即可,这样就大大节约了内存。
即适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码和数据有效分离(即耦合性降低),较好的体现了Java面向对象的设计思想。
public static void sleep(long millis) 单位是毫秒(该方法会抛出异常)
Thread.sleep(1000);
B:线程加入
public final void join() 等待该线程终止(为了使某线程先执行完毕)(该方法会抛出异常)
对象名.join(); // 该方法必须在启动线程后调用
C:线程礼让
public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。 能够在一定的程度上,让多个线程的执行更和谐,但是不能靠它保证一个线程一次。
Thread.yield();
D:后台线程(守护线程/用户线程)
public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程
对象名.setDaemon(true); // 设置守护线程
当正在运行的线程都是守护线程时,Java虚拟机退出。该方法必须在启动线程前调用。
E:中断(终止)线程(掌握)
public final void stop() 让线程停止,过时了,但是还可以使用。(为什么会过时呢?因为该方法太暴力了,具有固有的不安全性,直接把线程停止,该线程之后的代码都不能执行了)
对象名.stop();
public void interrupt() 中断线程。 把线程的状态终止,并抛出一个InterruptedException异常。
对象名.interrupt();
注意事项:
如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws。

原文:https://www.cnblogs.com/zyx110/p/10820315.html