在java中,线程A和线程B,堆内存和方法区共享
但是栈内存独立,一个线程一个栈
如果启动10个线程,那么就会有10个栈空间,每个栈空间之间互不干扰!!!各自执行各自的,这就是多线程并发!!!!
比如学校食堂就可以看作一个进程
食堂的一个个窗口就可以看作一个个线程,窗口A和窗口B之间 互不影响!!!!
所以多线程并发就是为了提高程序的处理效率!!
这边有一个问题!
使用多线程机制过后,main方法结束只是主线程结束了,主栈空了,其他栈可能还在压栈弹栈!!!
JVM java虚拟机是一个进程!!可以启动多个线程
多核CPU,,可以真正实现多线程并发!4核CPU可以在同一个时间点上,实现4个进程并发执行!!
什么叫真正实现多线程并发!!!
t1线程执行t1的
t2线程执行t2的 t1与t2之间互不影响!!
单核CPU不能真正实现多线程并发!只是给人一种多线程并发的错觉!!
对于单核CPU来说,在某一个时间点上实际上只能处理一件事情,但是计算机处理的速度极快,在多个线程之间频繁切换,加上人的反应是很慢的,所以给人一种错觉就是 多个事情在同时做!!
比如 线程A:qq音乐 和线程B:魔兽世界 线程A和线程B之间频繁切换,人就会感觉音乐在一直播放,游戏在一直运行!!
Java是支持多线程机制的!!实现线程有3个方式 1.定义一个MyThread直接继承java.lang.Thread ,重写run方法 2.定义一个类实现Runnable接口 3.定义一个类MyCallable实现Callable接口
第一种方式实现多线程!!
public class MyRunnableDemo01 {
public static void main(String[] args) {
//这就是一个主线程,这里的方法都在主线程中运行(也就是在主栈中运行!)
}
//定义了一个MyThread类继承Thread
public class MyThread extends Thread {
@Override
public void run() {
//这段程序运行在分支线程中(分支栈!!)
for (int i = 0; i < 100; i++) {
System.out.println("分支线程开始执行了"+i);
}
//获取当前分支线程的名字
System.out.println(Thread.currentThread().getName());
}
}
public class MyRunnableDemo01 {
public static void main(String[] args) {
//这就是一个主线程,这里的方法都在主线程中运行(也就是在主栈中运行!)
//创建了一个分支线程对象
MyThread t1 = new MyThread();
//启动线程
t1.start();
/*
start()方法的作用就是启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务结束之后,瞬间就结束。只要新的栈空间开辟出来,start()方法就立刻结束。
启动成功的线程,就会自动调用run()方法,并将run()方法压入分支栈底部
这边注意!!!!!!
run()方法在分支栈底部,main方法在主栈底部,两者平级!
还有一点需要注意!!
t1.start()和t1.run()的区别
t1.run()是直接调用类中的run方法,并没有开启一个 线程,还是单线程的情况,所以说只有在run()方法执行完毕之后,才会往下执行main中的程序!!
而t1.start()是开启了一个线程后,瞬间结束,之后调用run()方法,可以实现与主线程的并发(也就是两个for循环同时交替执行!!!)
*/
//以下的代码还是运行在主线程中!!
for(int i =0;i<=1000;i++)
{
System.out.println("主线程------>"+i);
}
}
第二种方法实现多线程
//定义了一个MyRunnable类 实现了Runnable接口
//这并不是一个线程类,是一个可运行的类。它还不是一个线程!!!
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("第二个线程的开启方式"+i);
}
}
}
//测试类
public class MyRunnableDemo01 {
public static void main(String[] args) {
//创建一个参数的对象
MyRunnable mr = new MyRunnable();
//创建了一个线程对象,并把参数传递给这个线程
//在线程启动后,执行的就是参数里面的run方法!!
Thread t1 = new Thread(mr);
//开启线程!!!
t1.start();
}
}
第二个方法比较常用,因为一个类实现了接口,还可以去继承其他的类,更灵活!!