1 什么是进程,什么是线程?
- 进程:进程是一个应用程序。
- 线程:是一个进程中的执行场景或者一个执行单元。
2 对于java程序来说,当在Dos命令窗口中输入:java HelloWorld回车之后,会先启动JVM,而JVM就是一个进程。JVM再启动一个主线程调用mian方法。同时再启动一个垃圾回收线程负责看护,回收垃圾。
因此,现在的java程序至少有两个线程并发。一个是垃圾回收线程,一个是执行main方法的主线程。
3 进程与线程的关系
- 进程A和进程B的内存独立不共享。
- 线程A和线程B:在java语言中,线程A和线程B堆内存和方法区共享内存,栈内存独立不共享,一个线程一个栈。
- 假设启动10个线程,会有10个栈空间,每个栈和每个栈之间互不干扰,各自执行各自的,这就是多线程并发。
4 思考:
使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束?
main方法结束知识主线程结束了,主栈空了,其他的栈(线程)可能还在压栈弹栈。
5 对于单核CPU来说,真的可以做到多线程并发吗?
例如:t1执行t1的,t2执行t2的,互不影响。
不能做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉。
对于单核cpu来说,在某个时间点上实际上只能处理一件事情,但是由于cpu的处理速度极快,多个线程之间频繁切换执行,给人的感觉是多个事情同时在做。
6 java语言中,实现线程有两种方式:
java支持多线程机制,并且java已经将多线程实现了,我们只需要继承就行了。
方式一:编写一个类,直接继承java.lang.Thread,重写run方法
public class ThreadTest02 {
public static void main(String[] args) {
//主线程
//新建一个分支线程对象
MyThread myThread = new MyThread();
//启动线程start();只是为了开启一个新的栈空间
myThread.start();//启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成后瞬间结束
for(int i=0;i<100;i++){
System.out.println("这里是主线程"+i);
}
}
}
class MyThread extends Thread{
//分支线程
@Override
public void run(){
for(int i=0;i<100;i++){
System.out.println("分支线程"+i);
}
}
}
myThread.start()解读
- 作用:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码在完成任务后,瞬间就结束了。同时线程也就启动成功了。
- 启动成功后:自动调用run()方法,并且run方法在分支栈的底部(压栈),run()方法在分支栈底部,main方法在主栈的底部。run和main都是平级的。【如果直接用myThread调用run方法,不会启动分支线程,此时还是单线程】。
方式二:编写一个类,实现java.lang.Runnable接口,实现run()方法;
import java.rmi.server.UnicastRemoteObject;
public class ThreadTest03 {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
for(int i=0;i<10000;i++){
System.out.println("这里是主线程eeeezzz"+i);
}
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
for(int i=0;i<10000;i++){
System.out.println("这里是分支"+i);
}
}
}
总结:这两种方式第二种好一些。接口除了实现接口,还能继承别的类,更灵活。
7 线程的生命周期
线程对象:
- 怎么获取线程对象?
Thread.currentThread(); - 怎么获取线程对象的名字?
t1.getName(“t1”) - 怎么修改线程对象?
t1.setName(“t1”)
线程sleep:staic void sleep(Long millis)
1.静态方法
2.参数是毫秒
3.让当前线程进入休眠状态,进入阻塞状态,放弃占有的cpu时间片,让给其他线程
public class ThreadTest06 {
public static void main(String[] args) throws InterruptedException {
Thread t= new MyRunnable();
//Thread t = new Thread(r);
t.start();
//让当前线程进入休眠状态,出现在main方法中,让main方法睡眠,并不是线程t睡眠
t.sleep(1000 * 10);//这里让main线程休息10秒执行接下来的代码,不影响分支线程的执行
System.out.println("主线程main");
}
static class MyRunnable extends Thread{
@Override
public void run(){
for (int i = 0;i<10;i++){
try {
Thread.sleep(1000);//每隔一秒打印一次
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("分支线程"+i);
}
}
}
}
唤醒睡眠的线程(不是中断线程的执行)
t.interrupt();//依靠java的异常处理机制
强行终止线程的执行
- 方法一:stop();会存在数据丢失的现象
- 方法二: 设置flag标记