• 0815(031天 线程/进程02)


    0815(031天 线程/进程02)

    每日一狗(田园犬西瓜瓜

    31

    线程/进程02

    1. 进程

    程序执行的整个过程叫做进程

    1.1 三大特性

    • 独立性
    • 动态性
    • 并发性

    1.2 问:僵尸进程个孤儿进程

    僵尸进程:子进程完了,父进程没有把子进程占用的资源进程回收,这个子进程就是僵尸进程(必须解决,站着内啥不内啥,严令禁止,杜绝浪费)

    孤儿进程:父进程比子进程先退出,他会被初始化进程init进程所收养,由init负责改进程的资源管理(占就占呗,反正还没跑完)

    1.3 并发和并行

    • 并行:多CPU同时执行一段处理逻辑,是真正的同时执行(不是反复横跳)
    • 并发:通过CPU调度算法,让人感觉是同时执行的,但是并不是,是他跑得快,你感觉不出来。同一时刻只有一个进程在执行

    1.4 问:进程和线程的区别

    • 调度:线程是CPU调度和分配的基本单位,进程是系统资源分配和调度的基本单位。
    • 并发性:不只是进程之间可以实现并发执行,同一个进程中的多个线程之间也可以并发执行。
    • 归属:一个进程至少拥有一个线程,一个线程只能也必须隶属于一个进程。
    • 拥有资源:进程是拥有资源的一个最小的独立单位,线程不拥有系统资源,线程可以访问,但产权还是进程的。
    • 操控者:进程是由操作系统来进行控制调度的,线程是由进程来进行调度处理的
    • 切换成本:线程自身的数据通常都存储在寄存器中,以及一个程序执行是使用的堆栈,所以线程之间切换的成本远低于进程之间的切换成本。
    • 独立性:同一进程中的线程本身就共享进程中的系统资源,彼此在调度会互相影响,而进程之间的资源都是互相独立的。

    2. 线程

    进程无法将CUP性能榨干,能让它闲着吗?不能够呀,聪明的开发人员由在进程之下划分了多个线程。

    2.1 主线程

    • 不是你写的程序起的,而是系统自动起的
    • 人为命名,没有什么特殊的地方,就是一个进程

    程序运行时,系统会先开一个进程,然后再自动开一个主线程,你的主方法就会在这个主线程中执行。

    虽然说主线程和进程中的其他进程没啥不一样的,但是所谓的主线程main可以在执行完处理逻辑后调用System.exit()。exit会让整个进程over终止,那所有线程自然都会退出。

    2.2 进程中的线程

    进程中的线程都是平级的,没有父子之分。

    • 单个线程只能属于单个进程,一个进程可以有多个线程
    • 进程中的线程共享系统分配给进程的所有资源(系统分配资源的最小单位就是进程)
    • 真正运行的是线程,而不是进程(进程是壳子,是用来存放资源的东西,而真正干活的是线程,进程不负责运行程序)
    • 线程在执行过程中需要协作同步

    2.4 多线程

    • 提高代码伸缩性(多线程的单核是并发,在多核是并行)
    • 提高CPU利用率(减少了CPU的空闲时间,你CPU先得有空闲时间我才有用,CPU忙的要死,你个这嘎嘎换,没什么用)
    • 基于Internet的应用有必要使用多线程

    不一定提高运行效率

    在大规模的计算时,cpu本身就忙着,在用多线程,cpu会将正在执行的程序相关数据进行存储,这是有时间代价的。

    这时候就需要进行线性扩展,让两个三个多个计算机来帮忙!

    缺点:上下文切换的开销

    代码实现

    不能直接调用run方法,直接调用就是单线程干的事

    执行过程不可重现 把握不住

    package com.yang2;
    
    public class Test01 {
    
    	public static void main(String[] args) {
    		Thread t1 = new Thread() {
    			public void run() {
    				for (int i = 0; i < 20; i++) {
    					System.out.println("左手重播"); // 阻塞200ms
    					try {
    						Thread.sleep(200);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		};
    		Thread t2 = new MyThread();
    		t1.start();
    		t2.start();
    
    	}
    
    }
    
    class MyThread extends Thread {
    	@Override
    	public void run() {
    		for (int i = 0; i < 20; i++) {
    			System.out.println("右手重播");
    			try {
    				Thread.sleep(200); // 阻塞200ms
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    线程启动时调用start()方法会默认调度执行其中的public void run() {}方法

    可以看到用run执行的程序的线程和主方法是统一个线程

    package com.yang2;
    
    public class Test02 {
    
    	public static void main(String[] args) {
    		System.out.println(Thread.currentThread()); 
            // Thread[main,5,main]
    		Thread t1 = new Thread() {
    			@Override
    			public void run() {
    				for (int i = 0; i < 10; i++) {
    					System.out.println("右手" + Thread.currentThread());
    					try {
    						Thread.sleep(20);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		};
    		t1.start(); // 右手Thread[Thread-0,5,main]
    		Thread t2 = new MyThread1();
    		t2.run(); // 左手Thread[main,5,main]
    	}
    
    }
    
    class MyThread1 extends Thread {
    	@Override
    	public void run() {
    		for (int i = 0; i < 10; i++) {
    			System.out.println("左手" + Thread.currentThread());
    			try {
    				Thread.sleep(20);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    2.5 问:实现线程的四种方法

    • 继承Thread(单根继承,使用受限)

      • 直接继承
      • 匿名内部类
    • 实现Runnable接口

      • 实现
      • 匿名内部类
      • lambda表达式
    • FutureTask可以有返回值的

    • 使用线程池

    Thread

    public class Test1 {
    public static void main(String[] args) {
    	System.out.println(Thread.currentThread()); //获取当前线程对象
    	//方法1.2
    	Thread t2=new Thread() {
    		@Override
    		public void run() {
    			for(int i=0;i<50;i++) {
    				System.out.println("右手慢动作重播"+Thread.currentThread());
    				try {
    					Thread.sleep(150);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	};
    //	t2.run();
    	Thread t1=new MyThread3();
    	t1.start();
    	t2.start();
    }
    }
    
    //方法1.1
    class MyThread3 extends Thread{
    	@Override
    	public void run() {
    		for(int i=0;i<50;i++) {
    			System.out.println("左手一个慢动作"+Thread.currentThread());
    			try {
    				Thread.sleep(200);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Runnable

    public class Test2 {
    	public static void main(String[] args) {
    		Thread t1 = new Thread(new MyRunnable());
    		t1.start();
    		// 方法2.2
    		new Thread(new Runnable() {
    			public void run() {
    				for (int i = 0; i < 10; i++) {
    					System.out.println("中间手...."+Thread.currentThread());
    					try {
    						Thread.sleep(100);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}).start();
    		// 方法2.3
    		new Thread(() -> {
    			for (int i = 0; i < 10; i++) {
    				System.out.println("右手...."+Thread.currentThread());
    				try {
    					Thread.sleep(100);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		}).start();
    	}
    }
    
    //方法2.1
    class MyRunnable implements Runnable {
    	public void run() {
    		for (int i = 0; i < 10; i++) {
    			System.out.println("左手...."+Thread.currentThread());
    			try {
    				Thread.sleep(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    FutureTask

    package com.yang2;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class Test06 {
    
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		// 为了获取返回值,所以需要使用FutureTask中提供的get方法
    		FutureTask<Integer>[] arr = new FutureTask[10];
    		for (int i = 1; i <= 10; i++) {
    			int begin = (i - 1) * 100 + 1;
    			int end = i * 100;
    			// 定义Callable的实现
    			Callable<Integer> c = new Callable<Integer>() {
    
    				@Override
    				public Integer call() throws Exception {
    					int res = 0;
    					for (int i = begin; i <= end; i++) {
    						res += i;
    					}
    					return res;
    				}
    			};
    			// 构建FutureTask对象,其中包含Callable对象
    			FutureTask<Integer> ft = new FutureTask<Integer>(c);
    			arr[i - 1] = ft;
    			// 启动线程,构建Thread对象时,要求参数类型为Runnable接口类型
    			// 线程执行时会自动调用run方法,而FutureTask中提供的run方法会调用Callable对象的call方法
    			new Thread(ft).start();
    		}
    		int res = 0;
    		for (FutureTask<Integer> tmp : arr) {
    			// main线程执行到这里时,会自动阻塞等待子线程tmp执行结束,执行结束后获取call方法的返回值
    			res += tmp.get();
    		}
    		System.out.println(res);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    线程池

    package com.yang2;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    public class Test08 {
    
    	public static void main(String[] args) {
            // 固定线程池
    //		ExecutorService es = Executors.newFixedThreadPool(3); // 就三个
            // 缓存线程池
    		ExecutorService es = Executors.newCachedThreadPool(); // 这有十个
    		FutureTask<Integer>[] arr = new FutureTask[10];
    		for (int i = 1; i <= 10; i++) {
    			int begin = (i - 1) * 100 + 1;
    			int end = i * 100;
    			arr[i - 1] = new FutureTask<>(new Callable<Integer>() {
    
    				@Override
    				public Integer call() throws Exception {
    					System.out.println(Thread.currentThread());
    					int res = 0;
    					for (int i = begin; i <= end; i++) {
    						res += i;
    					}
    					return res;
    				}
    			});
    			es.submit(arr[i - 1]);
    		}
    		int res = 0;
    		for (Future<Integer> tmp : arr) {
    			try {
    				res += tmp.get(1, TimeUnit.SECONDS);
    			} catch (InterruptedException | ExecutionException | TimeoutException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println(res);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    方法没有返回值

    想要将运算结果拿出来在计算就难受 了

    • 用实现类搞个属性,存起来
    package com.yang2;
    
    public class Test04 {
    
    	public static void main(String[] args) throws InterruptedException {
    		MyRunnable04[] arr = new MyRunnable04[10];
    		for (int i = 1; i <= 10; i++) {
    			MyRunnable04 r = new MyRunnable04((i - 1) * 100 + 1, i * 100);
    			arr[i - 1] = r;
    			new Thread(r).start();
    		}
    		Thread.sleep(2000);
    		for (MyRunnable04 r : arr) {
    			System.out.println(r.getRes());
    		}
    	}
    
    }
    
    class MyRunnable04 implements Runnable {
    	private int begin, end, res = 0;
    
    	public MyRunnable04(int begin, int end) {
    		this.begin = begin;
    		this.end = end;
    	}
    
    	public int getRes() {
    		return res;
    	}
    
    	@Override
    	public void run() {
    		for (int i = begin; i <= end; i++) {
    			res += i;
    		}
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 用全局变量实现类加
    package com.yang2;
    
    public class Test05 {
    	static int sum = 0;
    
    	public static void main(String[] args) throws InterruptedException {
    		for (int i = 1; i <= 10; i++) {
    			int begin = (i - 1) * 100 + 1;
    			int end = i * 100;
    			new Thread(new Runnable() {
    				@Override
    				public void run() {
    					int res = 0;
    					for (int i = begin; i <= end; i++) {
    						res += i;
    					}
    					sum += res;
    				}
    
    			}).start();
    		}
    		Thread.sleep(5000);
    		System.out.println(sum);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2.6 问:针对OOM

    OOM可能原因

    • 数据库的cursor没有及时关闭
    • 未关闭输入输出流
    • Bitmap使用后未调用recycle()
    • static等关键字
    • 非静态内部类持有外部类的引用context泄露
    • 流量/数据量峰值:在某一段时间内,他的使用需求量突然激增。超出了设计初期的阈值
    • 内存泄露

    2.7 线程池

    1. 一个池子
    2. 减少线程的创建,提高对象的服用,提升性能
    3. 核心线程、阻塞队列、工作流程、拒绝策略

    工作流程

    核心线程->阻塞队列->工作线程->饱和策略/拒绝策略

    001

    在这里插入图片描述

    核心线程永不回收(就是把已经存在的线程数量回收到核心线程数时就不回收了)

    问:一个构造器的参数

    public ThreadPoolExecutor(等等){}

    • int corePoolSize:核心线程数量
    • int maximumPoolSize,:线程池中允许的最大线程数
    • long keepAliveTime,:线程空闲最大时长
    • TimeUnit unit,:时长单位
    • BlockingQueue workQueue,:阻塞任务队列
    • ThreadFactory threadFactory,:线程工厂
    • RejectedExecutionHandler handler:拒绝策略/饱和处理策略

    应用

    package com.yang2;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    public class Test08 {
    
    	public static void main(String[] args) {
    //		ExecutorService es = Executors.newFixedThreadPool(3); // 就三个
    		ExecutorService es = Executors.newCachedThreadPool(); // 这有十个
    		FutureTask<Integer>[] arr = new FutureTask[10];
    		for (int i = 1; i <= 10; i++) {
    			int begin = (i - 1) * 100 + 1;
    			int end = i * 100;
    			arr[i - 1] = new FutureTask<>(new Callable<Integer>() {
    
    				@Override
    				public Integer call() throws Exception {
    					System.out.println(Thread.currentThread());
    					int res = 0;
    					for (int i = begin; i <= end; i++) {
    						res += i;
    					}
    					return res;
    				}
    			});
    			es.submit(arr[i - 1]);
    		}
    		int res = 0;
    		for (Future<Integer> tmp : arr) {
    			try {
    				res += tmp.get(1, TimeUnit.SECONDS);
    			} catch (InterruptedException | ExecutionException | TimeoutException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println(res);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    优点

    • 重用存在的线程,减少对象创建、消亡的开销,性能佳
    • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
    • 提供定时执行、定期执行、单线程、并发数控制等功能。

    享元模式

    用一个池子来管理一堆资源对象,需要的时候你来我这个池子要,池子给你一个,用完了不要释放对象,你在还给我这个池子,你下次再用,我再来问你要。

    公共接口:池子里的东西都间接或直接的实现该接口

    interface IShape {
    	void draw();
    }
    
    
    • 1
    • 2
    • 3
    • 4

    实现类:池子里放的东西

    class Circle implements IShape {
    
    	@Override
    	public void draw() {
    		System.out.println("这里是三角形");
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    调度管理类:要东西问这个类要,用完记得归还

    class ObjectManager {
    	static IShape[] arr = new IShape[20];
    	static {
    		for (int i = 0; i < 20; i++) {
    			arr[i] = new Circle();
    		}
    	}
    
    	public static IShape getInstance() {
    		IShape res = null;
    		for (int i = arr.length - 1; i >= 0; i--) {
    			if (arr[i] != null) {
    				res = arr[i];
    				arr[i] = null;
    				break;
    			}
    		}
    		return res;
    	}
    
    	public static void releaseInstance(IShape obj) {
    		for (int i = 0; i < arr.length - 1; i++) {
    			if (arr[i] == null) {
    				arr[i] = obj;
    				break;
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    测试类:有借有还再借不难,但是这个没用多线程,所以全都是第一个类

    package com.yang2;
    
    public class Test07 {
    
    	public static void main(String[] args) {
    		for (int i = 0; i < 100; i++) {
    			IShape tmp = ObjectManager.getInstance();
    			System.out.println(tmp);
    			ObjectManager.releaseInstance(tmp);
    		}
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.8 其他问题

    守护线程

    打辅助的

    当前进程中除了守护线程之外没线程了,守护线程这会就关了。

    线程组

    可以对线程组内的线程进行统一管理


    扩展小芝士

    • 并行的话要求软硬件同时支持并行才行。
    • 接手跑路代码(能不改源码就不改源码,要用人家的功能继承过来用)
    • juc包:并发包(java.util.concurrent)
    • 谈池字先谈享元模式
    • 单线程池子存在,还有用,控制性能
    • 线程池有叫执行框架
  • 相关阅读:
    第十四届蓝桥杯模拟赛(第二场)题解·2022年·C/C++
    Java--MyBatis传入参数parameterType
    PHP基础学习第十八篇(了解和学习PHP函数、$_GET和$_POST变量)
    蓝桥杯嵌入式史上最全最详细教程教你快速入门
    IOS硬件模拟定位原理
    Vue原理
    CTF-PWN-tips
    JUC中的设计模式
    三子棋小游戏(简单详细)
    MySQL——DQL union合并、limit限制与DDL建表和删表
  • 原文地址:https://blog.csdn.net/weixin_48015656/article/details/126354140