初步认识
目前我只是对java多线程有了一个初步的了解,所以写的东西很基础。在以后的学习中我将继续深入了解java多线程。
一 进程和多线程简介
1.1 进程和线程
当学习Java多线程时,会有人想为什么不用进程而用线程。说实话我也有这个疑问,为此我也特地到网上查了一下,了解了二者的概念与大致区别。
1.2 什么是进程?
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。如下图所示,在windows中通过查看任务管理器的方式,我们就可以清楚看到window当前运行的进程(.exe文件的运行)
1.3 什么是线程?
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
如图一个进程中有多个线程,多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器,栈区域。
其中程序计数器是一块内存区域,用来记录线程当前要执行的指令地址,那么程序计数器为何要设计为线程私有的呢?前面说了线程是占用 CPU 执行的基本单位,而 CPU 一般是使用时间片轮转方式让线程轮询占用的,所以当前线程 CPU 时间片用完后,要让出 CPU,等下次轮到自己时候在执行,那么如何知道之前程序执行到哪里了?其实程序计数器就是为了记录该线程让出 CPU 时候的执行地址,待再次分配到时间片时候就可以从自己私有的计数器指定地址继续执行了。
另外每个线程有自己的栈资源,用于存储该线程的局部变量,这些局部变量是该线程私有的,其它线程是访问不了的,另外栈还用来存放线程的调用栈帧。
堆是一个进程中最大的一块内存,堆是被进程中的所有线程共享的,是进程创建时候分配的,堆里面主要存放使用 new 操作创建的对象实例。
方法区则是用来存放进程中的代码片段的,是线程共享的。
1.4 什么是多线程?
多线程就是多个线程同时运行或交替运行。单核CPU的话是顺序执行,也就是交替运行。多核CPU的话,因为每个CPU有自己的运算器,所以在多个CPU中可以同时运行。
1.5 为什么提倡多线程而不是多进程?
线程就是轻量级的进程,是程序执行的最小单位。使用多线程而不是多进程去进行并发程序的设计,是因为线程间的切换和调度的成本远远小于进程。所以都提倡多线程
二 使用多线程的方式
实现线程最常用的两种实现线程的方式时继承thread和实现Runnable接口
2.1 继承Thread
public class Actor extends Thread{
public void run(){
}
}
2.2 实现Runnable接口
推荐实现Runnable接口开发多线程,因为java单继承但是可以实现多个接口。
public class ArmyRunnable implements Runnable {
public void run(){
}
}
三 如何停止线程
如今stop方法已经被弃用了,个人觉得比较好的方法就是设置停止旗标,这是线程的正常退出。如:
volatile boolean keeprunning=true;
四 Thread的一些方法
五 一个简单的实例—隋唐演义
这个实例是我看网课时老师讲的一个例子,我觉得这个例子挺好的,对理解java多线程很有帮助;个人也觉得这个例子蛮有趣的。
5.1 Actor.java
这段代码主要是写演员的一个线程,演员的一些介绍和动作。这里面涉及到了Thread里的getName()和sleep方法,还有线程的创建以及停止(此处用的是设置停止旗标方法)。
package com.thread;
public class Actor extends Thread {
public void run() {
System.out.println(getName()+"是一个演员");
int count=0;
boolean keeprunning=true;
while(keeprunning) {
System.out.println(getName()+"登台演出"+(++count));
if(count==100) {
keeprunning=false;
}
if(count%10==0) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println(getName()+"演出结束");
}
public static void main(String[] args) {
//线程的创建
Thread Actor=new Actor();//构造方法在对象创建的过程就被执行
Actor.setName("Mr.Thread");
//线程的开始
Actor.start();
//创建一个线程并且为其命名
Thread actreeThread=new Thread(new Actree(),"Ms.Runnable");
actreeThread.start();
}
}
class Actree implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"是一个演员");
int count=0;
boolean keeprunning=true;
while(keeprunning) {
System.out.println(Thread.currentThread().getName()+"登台演出"+(++count));
if(count==100) {
keeprunning=false;
}
if(count%10==0) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName()+"演出结束");//Thread.currentThread()为返回当前线程
}
}
5.2 ArmyRunnable.java
这段代码写的是军队的一些活动,这里通过循环遍历来控制军队的进攻与进攻次数。用到了Thread中的yield()方法。
package com.thread;
public class ArmyRunnable implements Runnable {
volatile boolean keeprunning=true;
@Override
public void run() {
while(keeprunning) {
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getName()+"进攻对方["+i+"]");
//释放该线程,让几个线程来同时参与竞争
Thread.yield();
}
}
System.out.println(Thread.currentThread().getName()+"进攻结束");
}
}
5.3 KeyPersonThread.java
关键人物,进攻活动。
package com.thread;
public class KeyPersonThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName()+"战斗开始了");
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName()+"左突右杀,攻击了随军["+i+"]");
}
System.out.println(Thread.currentThread().getName()+"战斗结束了");
}
}
5.4 stage.java
舞台,将给军队和关键人物活动的场所。
package com.thread;
public class stage extends Thread {
public void run() {
System.out.println("欢迎大家收看隋唐演义");
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("大幕徐徐拉开");
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ArmyRunnable armyD=new ArmyRunnable();
ArmyRunnable armyR=new ArmyRunnable();
//创建线程,,,,2条线程
Thread army1=new Thread(armyD,"隋军");
Thread army2=new Thread(armyR,"农民军");
//启动多线程
army1.start();
army2.start();
//舞台休眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("当双方大军交战激烈之际,半路杀出个程咬金!");
armyD.keeprunning=false;
armyR.keeprunning=false;
try {
Thread.sleep(2000);
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
//创建线程
Thread Keyperson=new Thread(new KeyPersonThread(),"程咬金");
Keyperson.start();
try {
Keyperson.join();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("程咬金是个弟中弟....,程咬金被杀");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("战争结束,人们继续生活在水深火热之中");
System.out.println("隋唐演义结束");
}
public static void main(String[] args) {
Thread stage=new stage();
stage.start();
}
}
六 收获
通过一段时间的学习,我对java多线程有了一个初步的了解。也通过慕课老师隋唐演义的实例对学的知识点有了很好的巩固,也激发了我学习的兴趣。在此之后我将继续多线程的学习,了解更对的多线程知识。
本人是一个初学者,如有写的不好的地方请各位大佬指出,感谢!