书中自有颜如玉,书中自有黄金屋
接下来一段时间一边工作,一边跟书学习高并发,来提高自己的能力,充实自己的知识量
程序
程序是认为编写的程序或者某种方式自动生成的代码,能够保存到文件中,程序本身是静态的.如果要运行程序,则需要将程序加载到内存中,通过编译器或解释器将其编译成计算机能够理解的方式运行
进程与线程
**进城是操作系统进行资源分配的最小单位**,在一个进程中可以创建多个线程
**线程是比进程粒度更小的能够独立运行得基本单位**,也是cpu调度的最小单位,被称为轻量级的进程
在一个进程中可以创建多个线程,多个线程各自拥有独立的局部变量,线程和堆栈和程序计数器等,能够访问共享的资源
** 进程与线程的区别**
进程是操作系统分配资源的最小单位,进程是CPU调度的最小单位
一个进程中可以创建多个线程,一个线程只能属于一个进程
进程与进程之间是相互独立的,进程内部的线程之间并不完全独立,可以共享进程的堆内存,方法去内存和系统资源
进程上下文的切换要比线程的上下文切换慢得多
进程是存在地址空间的,而线程本身无地址空间,线程的地址空间是包含在进程中的
某个进程发生异常不会对其它进程造成影响,某个线程发生异常可能会对所在进程中的其他线程造成影响
线程组
线程组可以同时管理多个线程.在实际应用中,如果系统创建的线程比较多,创建的线程也比较多明确,就可以将具有相同功能的线程放到一个线程组中
线程组的使用
package com.lifly.threadGroup;
/**
* @ClassName ThreadGroupTest
* @Description TODO
* @Author lifly
* @Date 2022/7/5 21:21
* @Version 1.0.0
**/
public class ThreadGroupTest {
public static void main(String[] args) {
//创建线程组
ThreadGroup threadGroup = new ThreadGroup("threadGroup");
//创建线程1,并在线程中传入线程组和线程名称
Thread thread1 = new Thread(threadGroup, () -> {
String groupName = Thread.currentThread().getThreadGroup().getName();
String threadName = Thread.currentThread().getName();
System.out.println(groupName + ":" + threadName);
}, "thread1");
//创建线程2
Thread thread2 = new Thread(threadGroup,()->{
String groupName = Thread.currentThread().getThreadGroup().getName();
String threadName = Thread.currentThread().getName();
System.out.println(groupName + ":" + threadName);
},"thread2");
thread1.start();
thread2.start();
}
}
用户线程和守护线程
用户线程
用户线程是最常见的线程,比如在程序启动时,JVM调用程序的main()方法就会创建一个用户线程
创建用户线程
package com.lifly.userThread;
/**
* @ClassName ThreadTest
* @Description TODO
* @Author lifly
* @Date 2022/7/5 21:33
* @Version 1.0.0
**/
public class ThreadTest {
public static void main(String[] args) {
//创建用户线程
Thread thread = new Thread(() -> {
System.out.println("用户线程");
}, "ThreadUser");
thread.start();
}
}
用户线程是一种特殊的线程,这种线程在系统后台完成相应的任务,例如JVM中的垃圾回收及线程,JIT编译线程都是守护线程
在程序运行的过程中,只要有一个非守护线程还在运行,守护线程就会一直运行,只有所有的非守护线程全部运行结束,守护线程才会退出.
在编写java程序时,可以手动指定当前线程是否是守护线程,直接调用Thread对象的setDeamon()方法,传入true即可.
以下代码是将线程设置为守护线程
package com.lifly.userThread;
/**
* @ClassName ThreadTest
* @Description TODO
* @Author lifly
* @Date 2022/7/5 21:33
* @Version 1.0.0
**/
public class ThreadTest {
public static void main(String[] args) {
//创建用户线程
Thread thread = new Thread(() -> {
System.out.println("守护线程");
}, "ThreadUser");
thread.setDaemon(true);
thread.start();
}
}
并发与并行
并行指多核CPU中的一个CPU核心执行线程时,另一个CPU核心能够同时执行另一个线程,两个线程不会抢占CPU资源,可以同时执行.
并发指在一段时间内CPU处理了多线程,这些线程会抢占CPU的资源,CPU资源根据时间片周期在多个线程之间来回切换,多个线程在同一段时间内同时运行,而在同一时刻实际不是同时运行的.
并行与并发的区别
并行之多个线程在一段时间的每个时刻都同时在运行,并发之多个线程在一段时间内(而非同一时刻)同时运行
并行执行的多个任务之间不会抢占CPU资源,并发执行的多个任务会抢占CPU资源
并行只有在多核CPU或者多CPU的情况下才会发生,在单核CPU中只可能发生串行执行或者并发执行
同步和异步
同步和异步主要是这对一次方法的调用来说的.已同步方式调用来说,必须在方法返回信息后,才能执行后面的操作.而以异步方式调用方法时,不必等方法返回信息,就可以执行后面的操作,当完成被调用的方法逻辑后,会以通知或者回调的方法告知调用方法
共享与独享
共享指多个线程在运行过程中共享某些资源,而独享指一个线程在运行过程中独占某个系统资源.
例如在java程序运行的过程中,JVM中的方法区和堆空间是线程共享的,而栈,本地方法和程序计数器是每个线程独占的,也就是独享的.
临界区
临界区一般表示能够被多个线程共享的资源或数据,但是每次只能提供给一个线程使用,临界区资源一旦被占用,其他线程就必须等待.
在并发编程中,临界区一般指受保护的对象或程序代码片段,可以通过加锁的方式保证每次只有一个线程进入临界区,从而达到保护临界区的目的
阻塞与非阻塞
阻塞与非阻塞一般用来描述多个线程之间的相互影响.例如,在并发编程中,多个线程抢占一个临界区资源,如果其中一个线程抢占成功,那么其他的线程必须阻塞等待.在占用临界区资源的线程执行完毕,释放临界区资源后,其他线程可以再次抢占临界区资源.
如果占用临界区资源的线程一直不释放资源,其他线程则会一直阻塞等待
非阻塞线程之间不会相互影响,所有的线程都会继续执行.