线程和进程

进程

  • 进程是执行中的程序,是动态的,程序是静态的
  • 进程是操作系统分配资源的最小单位,有一个进程控制块(PCB)和唯一的进程标识符(PID)
  • 进程之间相互独立,内存不共享
  • 每个进程都是一个实体,每个进程都有属于自己的一块内存
  • 由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全——>进程的创建、销毁、切换开销比较大
  • 进程只能创建子进程,无法创建平级进程

线程

  • 线程是CPU的基本调度单位,是比进程更小的能独立运行的基本单位.
  • 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  • 一个进程可能包含多个线程,一个进程下的多个线程可以共享进程的内存区域
  • 不同进程之间的线程相互不可见
  • 一个线程可以创建和撤销另一个线程

并发和并行

线程并发就是两个以上线程在同一时间段在运行,cpu资源一直在切换分配多个线程。但某一时间点,必然只有一个线程在运行(单核CPU情况下)
并发指的是两个或者多个在同一时刻运行,相互不影响,资源独立。(多核CPU)

守护线程和非守护线程

典型代表:
守护:垃圾回收器
非守护:main(JVM启动的时候调用)
在JVM启动时,实际上有多个线程,但至少由一个非守护线程mian

创建方式

  1. 继承Thread类,实现一个run方法,直接使用.start()方法进行启动
    在这里插入图片描述在这里插入图片描述

嫌麻烦可以直接这样:
在这里插入图片描述
3. 实现Runable接口,实现run方法,将实现接口的类作为参数传入Thread类中,之后使用Thread的run方法
在这里插入图片描述
在这里插入图片描述调用start的时候,至少有两个线程出现,一个时调用你的线程,一个是被调用启动的线程

线程生命周期

new、runnable、running、block、terminated
在这里插入图片描述

Thread和Runable区别和联系

runable接口将可执行的逻辑单元和线程控制分离开来
以银行家叫号说明为例:

/**
* 叫号类
* */
public class Ticket extends Thread{

    private static int MAX = 50;
    private final String name;
    /*
    加static只会在类初始化的时候实例化一次,多个线程共享index变量,但并发量大的时候依然会发生跳号,重号和超过最大值
    不加的话每次实例化一个Ticket都会初始化index,它们之间不互通
     */
    private static int index = 1;

    public Ticket(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        while(index<=MAX){
            System.out.println(name +"call"+index++);
        }
    }
}

/**
* 银行类
* /
public class Bank {
    public static void main(String[] args) {
    //实例化三次继承了thread的类
        Ticket t1 = new Ticket("1号柜台");
        t1.start();
        Ticket t2 = new Ticket("2号柜台");
        t2.start();
        Ticket t3 = new Ticket("3号柜台");
        t3.start();

    }
}

输出如下:使用static,基本实现共享index
在这里插入图片描述

实现runable

public class Ticket1 implements Runnable {
    private static int MAX = 50;
    private static int index = 1;

    @Override
    public void run() {
        while(index<=MAX){
            System.out.println( Thread.currentThread()+"call : "+index++);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public static void main(String[] args) {
//实例化一次实现runable的类
        final Ticket1 t11 = new Ticket1();//添加final,变量不能指向别的引用变量了就
        Thread tt1 = new Thread(t11,"一号窗口");
        Thread tt2 = new Thread(t11,"二号窗口");
        Thread tt3 = new Thread(t11,"三号窗口");
        tt1.start();
        tt2.start();
        tt3.start();
    }

在这里插入图片描述
以上两种输出其实都会有重复甚至是52输出(我只截了部分),说明什么?说明线程不安全啊
runnable的优势:实现的方式没有类的单继承性的局限性; 实现的方式更适合来处理多个线程有共享数据的情况。

协程

  • 轻量级线程
  • 协程由用户自己调度
  • 协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

进程和线程的区别

  • 一个程序至少有一个进程,一个进程至少有一个线程
  • 进程自己独有的内存单元,多个线程共享进程的内存区域
  • 一个进程死掉对于其它进程没有影响,但是一个线程死掉(非正常退出或者死循环)可能会影响其它线程正常工作(它不放手手里的资源),所以多线程程序没有多进程健壮。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值