轻松理解进程与线程
1.程序,进程,线程
- 程序是指令和数据的有序集合,是一个静态的概念。
- 进程是执行程序的一次执行过程,是动态的概念,系统分配资源的单位。
- 通常一个进程包含若干个线程,线程是CPU调度和执行的单位。
1.1 普通方法和多线程
2. 线程创建
2.1 Thread class
//继承Thread类,重写run方法,调用start开启线程
public class Test001 extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("我想睡觉了。。。"+i);
}
}
public static void main(String[] args) {
//main主线程
System.out.println("主线程调用---");
//创建线程对象,并且start开启
Test001 ts=new Test001();
ts.start();
}
}
2.2 Runnable 接口
定义MyRunnable实现Runnable接口
实现run()方法,调用start()方法启动线程
推荐使用Runnable接口,因为java的单继承类,多继承接口的性质。
2.3 Callable 接口
- 特点
可以定义返回值
可以抛出异常
2.4 Lamda 表达式
- 避免了匿名内部类定义过多
- 实质属于函数式编程
2.4.1函数式接口
- 任何接口只包含唯一一个抽象方法,称为函数式接口
- 对于函数式接口,可以通过Lamda表达式创建该接口对象
//定义一个接口
interface ILove{
void love(int a);
}
//静态实现类在类中
static class Love implement ILove{
public void love(int a){
sout(a);
}
}
//局部内部类在main方法中
class Love implement ILove{
public void love(int a){
sout(a);
}
}
//上面两种这样实现
ILove lo =new Love();
lo.love(2);
//匿名内部类
ILove lo =new ILove(){
public void love(int a){
sout(a);
}
};
lo.love(2);
//lamda表达式
ILove lo=(int a)->{
sout(a)
}
lo.love(50);
//lamda简化(参数类型,括号,花括号都可以化简)
ILove lo=null;
lo=a->sout(a);
//总结:化简括号和花括号需要只有一个或一行数据
//并且接口必须是函数式接口
2.5静态代理模式
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实对象
- 静态代理优势
- 代理对象可以执行真实对象无法实现的事情
- 真实对象只需要完成自身核心内容
You you =new You();
WeddingCompany wc =new WeddingCompany();
WeddingCompany.HappyMarry();
2.6并发问题
当多个线程操作同一资源时,线程不安全,数据紊乱
3. 线程5状态
3.1 概述
线程方法
3.2 线程停止
- 线程正常停止》循环一定的次数
- 使用标志位》设置boolean类型
3.3 线程休眠
- sleep(time ms)时间单位为毫秒
- sleep时间达到后,线程进入就绪状态
- sleep可以模拟网络延时,倒计时等
- 每一个对象都有一个锁,sleep不会释放锁
3.4线程礼让
- 让当前线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让CPU重新调度,但不一定成功
3.5 线程优先 join
Join合并线程,待此加入线程执行完后,再执行其他线程,其他线程阻塞
3.6 线程优先级
- Java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
- 线程按照优先级用数字表示,从1~10
- 使用以下方式改变或获取优先级
- getPriority()
- setPriority(int x)
注:线程的优先级低,仅仅意味着获得调度的概率低,但不绝对。
3.7 守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 守护线程有:后台记录操作日志;监控内存;垃圾回收等待等。
4. 线程同步
4.1概念
-
并发与并行
并发是指在某一时段内,同时进行的事情,称为并发。
举例:就像一边听课,一边看电视,在一个小时范围内,看起来像是边看电视边上课;但是实际上大脑是一次执行一件事情,看3分钟电视,后听了5分钟的课,最后在1小时内,两件事情都完成了。两件事是串行执行结束的,但是在1小时这个大时间段内,是“同时完成的”。并行就是真正意义上的同时执行。
举例:就像双行马路上的两辆摩托车,他们可以并排骑行,就是并行。 -
同步与异步
同步:是指系统一直监测整个事情执行全过程,直到事情执行结束。
举例:就像去冰箱店买冰箱,同步就是你自己一直跟着店里的师傅把你的冰箱打包,装车,送到你家这个全过程。 (这样同步的代价就在于浪费了你的大量时间,你在此期间不能做其他事情,效率低下。)异步:是指将消息发送或者让事情执行,不去全程监测,只看最后结果即可。
举例:还是买冰箱,异步就是你去买冰箱,交了钱就走了,没有查看冰箱在哪,最后回家等师傅把冰箱送到家,事情就算结束了。(这样异步明显效率提高了很多,但是会存在安全隐患,就是碰见了厂家次品把你的好冰箱中途调包了,你最后收到了一个破冰箱这样的问题。)
4.2 线程同步
队列+锁
5. 死锁
多个线程互相持有对方需要的资源,且都不放开。
5.1 Lock锁
5.2 线程通信
生产者与消费者问题
5.2.1管程法
public class TestPC {
//生产者消费者模型--->利用缓冲区解决:管程法
public static void main(String[] args) {
SynContainter synContainter=new SynContainter();
new Product(synContainter).start();
new Consumer(synContainter).start();
}
}
//生产者
class Product extends Thread{
SynContainter synContainter;
public Product(SynContainter synContainter){
this.synContainter=synContainter;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
synContainter.prodpush(new Chicken(i));
System.out.println("生产了"+i+"个鸡");
}
}
}
//消费者
class Consumer extends Thread{
SynContainter synContainter;
public Consumer(SynContainter synContainter){
this.synContainter=synContainter;
}
@Override
public void run() {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 1; i <= 100; i++) {
System.out.println("消费了"+synContainter.constpop().id+"个鸡");
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id=id;
}
}
//缓冲区
class SynContainter{
//生成产品数组
Chicken[] ck=new Chicken[10];
int count=0;
//生产者方法
public synchronized void prodpush(Chicken chicken){
//当产品满了时,生产者等待
if(count==ck.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//产品不满时,就往进生产
ck[count]=chicken;
count++;
//通知消费者可以消费
this.notify();
}
//消费者方法
public synchronized Chicken constpop(){
//当产品为空时,消费者等待
if (count==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//否则就消费
count--;
Chicken getchicken=ck[count];
//通知消费者可以生产
this.notify();
return getchicken;
}
}
5.2.2 信号灯法
public class TestPc2 {
public static void main(String[] args) {
Eat eat=new Eat();
new Product2(eat).start();
new consumer2(eat).start();
}
}
//生产者
class Product2 extends Thread{
Eat eat;
public Product2(Eat eat) {
this.eat = eat;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.eat.playfood("西瓜");
}
}
}
//消费者
class consumer2 extends Thread{
Eat eat;
public consumer2(Eat eat) {
this.eat = eat;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.eat.eatfood();
}
}
}
//生产消费方法
class Eat{
String food;
boolean flag=false;
//生产者方法
public synchronized void playfood(String food){
//如果食物还在,就不用生产了
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("师傅做了"+food);
this.notify();
flag=!flag;
//为了告诉消费者师傅做了什么
this.food=food;
}
//消费者方法
public synchronized void eatfood(){
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者吃了"+food);
this.notify();
flag=!flag;
}
}
5.2.3 线程池
总结
线程创建的三种方法如下
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test003 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
new MyThread().start();
new Thread(new MyThread2()).start();
FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new MyThread3());
new Thread(integerFutureTask).start();
Integer integer = integerFutureTask.get();
System.out.println(integer);
}
}
//方法1
class MyThread extends Thread{
@Override
public void run() {
System.out.println("Mythread01");
}
}
//方法2
class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("Mythread02");
}
}
//方法3
class MyThread3 implements Callable{
@Override
public Integer call() throws Exception {
System.out.println("Mythread03");
return 520;
}
}
public void run() {
System.out.println(“Mythread01”);
}
}
//方法2
class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println(“Mythread02”);
}
}
//方法3
class MyThread3 implements Callable{
@Override
public Integer call() throws Exception {
System.out.println(“Mythread03”);
return 520;
}
}
* 文章中部分图片采用狂神教学视频,仅做学习参考,感谢。