进程和线程
参考文章:https://www.cnblogs.com/java1024/archive/2019/11/28/11950129.html
面试重点:java虚拟机,集合,线程
java的内存模型
栈:引用
堆:占内存最大,存放对象,gc回收的是堆空间
方法区:存储class,static信息
程序计数器:cpu执行1,2,3.程序计数器保存上个程序执行的位置,程序是一个个执行,记住序号。
本地方法栈:使用其他语言编写的程序方法,本地方法保存在动态链接库中,即.dll(windows系统)文件中,格式是各个平台专有的。通过本地方法,JAVA程序可以直接访问底层操作系统的资源,如果你这样用,你的程序就变成平台相关了,因为本地方法的动态库是与平台相关的,此外使用本地方法还可能把程序变得和特定的JAVA平台实现相关。
线程是轻量级进程
线程和进程的区别
1.一个进程可以有多个线程,而一个线程至少要有一个父进程。
2.线程可以有自己的堆栈,程序计数器和局部变量。
3.线程和进程和其他线程共享进程所有资源。
4.独立运行,采用抢占方式(切换具体那个线程抢占使用cpu时间)。
5.一个线程可以创建和删除另外一个线程。
6.同一个进程中的多个线程之间可以并发执行(可以理解为快速切换,使用cpu时间)。
7.线程的调度管理是有进程来完成的。
关键词:并发,抢占,多线程,共享资源,独自堆栈

什么是进程
进程是程序的一次动态执行过程,它需要经历:代码加载,代码执行,代码结束的完整的过程。也是一个过程从产生,发展到最终消亡的过程。
多进程操作系统是能够运行多个进程(程序),CPU具有分时机制,每个进程都能循环获得自己的CPU时间片,由于CPU执行速度非常快,使得所有的程序都好像是同时进行一样。
什么是线程
线程和进程一样,都是实现并发的一个基本单位。线程是比进程更小的执行单位线程是进程的基础上进行的进一步的划分。
多线程是指在执行过程中可以产生更多的程序单元。这些更小的单元称为线程。线程可以同时存在。同时运行,一个进程可能包含多个同时执行的线程,
线程和进程的区别如下:
线程的状态变化:创建状态,就绪状态,运行状态,阻塞状态,死亡状态。
创建状态
在程序中用构造方法创建了一个线程对象后,新的线程对象状态就处于新建状态。此时他已经有了相应的内存空间和其他资源,但还是处于不可运行的状态,
Thread类的构造方法了实现,
例:Thread thread = new Thread
就绪状态
调用线程start()方法就可以启动线程,当线程启动是,线程就进入就绪状态。此时线程就进入线程队列排队,等待CPU服务,表明它已经具备了运行条件。
运行状态
当就绪状态被调用并获得处理器资源时,线程就进入了运行状态,此时,自动调用该线程对象的run()方法。run()方法定义该线程的操作和功能。
阻塞状态
一个正在执行的线程在某种特殊的情况下,如果被人挂起或需要执行耗时的输入、输出操作,会让CPU暂时终止自己的执行,进入阻塞状态。在可执行状态下,调用sleep(),suspend(),wait()等方法,线程都可进入阻塞状态,发生阻塞状态时线程不能进入排队队列,只有当引起的阻塞的原因被消除后,线程才可进入就绪状态。
死亡状态
线程调用stop()方法时或run() 方法执行结束后,即处于死亡状态。处于死亡状态的线程不能有继续运行的能力。
在此提出一个问题,Java 程序每次运行至少启动几个线程?
回答:至少启动两个线程,每当使用 Java 命令执行一个类时,实际上都会启动一个 JVM,每一个JVM实际上就是在操作系统中启动一个线程,Java 本身具备了垃圾的收集机制。所以在 Java 运行时至少会启动两个线程,一个是 main 线程,另外一个是垃圾收集线程。
java中线程的实现方式(继承Thread类和实现Runnable接口)
实现Runnable接口
class MyThread implements Runnable{ // 实现Runnable接口,作为线程的实现类
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
};
public class RunnableDemo01{
public static void main(String args[]){
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
Thread t1 = new Thread(mt1) ; // 实例化Thread类对象
Thread t2 = new Thread(mt2) ; // 实例化Thread类对象
t1.start() ; // 启动多线程
t2.start() ; // 启动多线程
}
};
运行结果

实现Thread类继承
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
};
public class ThreadDemo02{
public static void main(String args[]){
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
mt1.start() ; // 调用线程主体
mt2.start() ; // 调用线程主体
}
运行结果

线程调用的是start()方法,但是运行的是run()方法
Thread类继承 和 Runnable接口的区别
public class Thread extends Object implements Runnable
Thread类也是Runnable接口的子类。但是Thread类没有完全实现Runnable接口中的run()方法
亲自实践
import java.util.*;
public class text {
public static void main(String[] args) {
text2 te = new text2(); //创建一个对象
Thread ti = new Thread(te);//创建一个Thread对象
ti.start(); //打开线程
text3 t2 = new text3(); //创建一个Thread子类对象
t2.start(); //打开线程
}
}
class text2 implements Runnable{ //扩展Runnable接口
@Override
public void run() {
System.out.println("this is runnable");
try { //使用线程休眠模板
Thread.sleep(5000); //线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("this is runnable");
}
}
class text3 extends Thread{ //继承Thread
@Override
public void run() {
System.out.println("this is thread");
}
}
运行结果

线程的使用方法
start() //开始方法
Thread.sleep() //线程休眠方法,有固定语法try{}catch{}
对象名.setDarmon(true); //此线程在后台运行
线程优先级:
public static void main(String args[]){
Thread t1 = new Thread(new MyThread(),"线程A") ; // 实例化线程对象
Thread t2 = new Thread(new MyThread(),"线程B") ; // 实例化线程对象
Thread t3 = new Thread(new MyThread(),"线程C") ; // 实例化线程对象
t1.setPriority(Thread.MIN_PRIORITY) ; // 优先级最低
t2.setPriority(Thread.MAX_PRIORITY) ; // 优先级最高
t3.setPriority(Thread.NORM_PRIORITY) ; // 优先级最中等
t1.start() ; // 启动线程
t2.start() ; // 启动线程
t3.start() ; // 启动线程
}
};
线程礼让:Thread.currentThread().yield() ; // 线程礼让
同步以及死锁
一个多线程的程序如果是通过Runnable 接口实现的,则意味着类中的属性被多个线程共享,那么这样就会造成一种问题,如果要同时操作同一个资源时就有可能出现资源同步问题。
解决方法:
同步代码块:
synchronized(同步对象){
需要同步的代码
}**
private int ticket = 5 ; // 假设一共有5张票
public void run(){
for(int i=0;i<100;i++){
synchronized(this){ // 要对当前对象进行同步
if(ticket>0){ // 还有票
try{
Thread.sleep(300) ; // 加入延迟
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("卖票:ticket = " + ticket-- );
}
}
}
}
};
public class SyncDemo02{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 定义线程对象
Thread t1 = new Thread(mt) ; // 定义Thread对象
Thread t2 = new Thread(mt) ; // 定义Thread对象
Thread t3 = new Thread(mt) ; // 定义Thread对象
t1.start() ;
t2.start() ;
t3.start() ;
}
};
程序执行结果

同步方法
除了可以将需要的代码设置成为同步代码块外,也可以使用synchronized关键字讲一个方法声明为同步方法。
synchronized 方法返回值 方法名称(参数列表){
}
private int ticket = 5 ; // 假设一共有5张票
public void run(){
for(int i=0;i<100;i++){
this.sale() ; // 调用同步方法
}
}
public synchronized void sale(){ // 声明同步方法
if(ticket>0){ // 还有票
try{
Thread.sleep(300) ; // 加入延迟
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("卖票:ticket = " + ticket-- );
}
}
};
public class SyncDemo03{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 定义线程对象
Thread t1 = new Thread(mt) ; // 定义Thread对象
Thread t2 = new Thread(mt) ; // 定义Thread对象
Thread t3 = new Thread(mt) ; // 定义Thread对象
t1.start() ;
t2.start() ;
t3.start() ;
}
};
执行结果

死锁
同步可以保证资源共享操作的正确性,但是过多的同步也会产生问题,例如:张三想要李四的画,李四想要张三的书,张三对李四说“把你的画给我,我就给你书”,李四也对张三说“把你的书给我,我就给你画”。两个人相互等对方先行动,就怎么干等没有结果。这实际就是死锁的概念。
死锁:就是两个线程都在等待对方先完成,造成程序的停滞,一般程序的死锁都是在程序在运行的时候出现的
实例:
public void say(){
System.out.println("张三对李四说:“你给我画,我就把书给你。”") ;
}
public void get(){
System.out.println("张三得到画了。") ;
}
};
class Lisi{ // 定义李四类
public void say(){
System.out.println("李四对张三说:“你给我书,我就把画给你”") ;
}
public void get(){
System.out.println("李四得到书了。") ;
}
};
public class ThreadDeadLock implements Runnable{
private static Zhangsan zs = new Zhangsan() ; // 实例化static型对象
private static Lisi ls = new Lisi() ; // 实例化static型对象
private boolean flag = false ; // 声明标志位,判断那个先说话
public void run(){ // 覆写run()方法
if(flag){
synchronized(zs){ // 同步张三
zs.say() ;
try{
Thread.sleep(500) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
synchronized(ls){
zs.get() ;
}
}
}else{
synchronized(ls){
ls.say() ;
try{
Thread.sleep(500) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
synchronized(zs){
ls.get() ;
}
}
}
}
public static void main(String args[]){
ThreadDeadLock t1 = new ThreadDeadLock() ; // 控制张三
ThreadDeadLock t2 = new ThreadDeadLock() ; // 控制李四
t1.flag = true ;
t2.flag = false ;
Thread thA = new Thread(t1) ;
Thread thB = new Thread(t2) ;
thA.start() ;
thB.start() ;
}
};

程序不再执行,进入死锁状态
本文详细介绍了Java中的线程和进程概念,包括它们的区别、状态转换以及Java线程的实现方式。线程作为轻量级进程,允许多个执行单元在同一个进程中并发执行,而进程是程序的一次动态执行过程。Java中线程可以通过继承Thread类或实现Runnable接口来创建。文章还讨论了线程同步和死锁问题,展示了如何避免资源竞争和死锁状况的发生。

2万+

被折叠的 条评论
为什么被折叠?



