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();
			}
		}
	}
}

线程启动时调用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();
			}
		}
	}
}

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();
			}
		}
	}
}

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();
			}
		}
	}

}

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);
	}

}

线程池

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);
	}

}

方法没有返回值

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

  • 用实现类搞个属性,存起来
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;
		}

	}

}
  • 用全局变量实现类加
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);
	}

}

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);
	}

}

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

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

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

interface IShape {
	void draw();
}

实现类:池子里放的东西

class Circle implements IShape {

	@Override
	public void draw() {
		System.out.println("这里是三角形");

	}
}

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

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;
			}
		}
	}
}

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

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);
		}

	}

}

2.8 其他问题

守护线程

打辅助的

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

线程组

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


扩展小芝士

  • 并行的话要求软硬件同时支持并行才行。
  • 接手跑路代码(能不改源码就不改源码,要用人家的功能继承过来用)
  • juc包:并发包(java.util.concurrent)
  • 谈池字先谈享元模式
  • 单线程池子存在,还有用,控制性能
  • 线程池有叫执行框架
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值