JAVA基础之多线程知识总结

一、基础知识

1.定义

  1. 进程
    简单来说,进程就是指正在运行的程序。也就是说,当一个程序进入内存运行,就变成了一个进程。进程中包含一个或多个线程。
    单进程中的单线程:main方法从入口到结束,一条路走到底。目前对初学者来说所学的Java基础只涉及单进程中的单线程和单进程中的多线程。

  2. 线程
    线程是一个进程中的执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个程序也可以称为多线程程序。

2.线程和进程的区别

①一个进程至少有一个线程,线程的划分尺度小于进程,是进程中的一个执行单元。
②进程应有独立的内存单元,而多个线程共享这些内存单元,从而极大地提高了程序的运行效率。
③进程可以独立运行,但线程必须依附于进程执行,不能独立运行。

3.原理

进程和线程是并发运行的,简称“并发”,不是同时运行(并行)的。
并发:在同一时间间隔内发生
并行:同一时间发生

4.线程状态

1.就绪状态:New线程后,该线程具有可运行的资格,等待进入运行状态。
2.执行状态:指运行状态,线程调用start()方法后,进入正在运行状态。
3.阻塞状态:当线程等待后,可能会成为受阻塞状态。
4.新建状态:New线程
5.结束状态:线程运行完等待回收。

5.创建线程的方法及原理

创建线程共有三种方法。

1、继承Thread类
步骤:
①定义一个类继承Thread类
②重写run()方法
③主函数中创建子类对象就是创建线程对象
④调用start()方法,开启线程并让线程执行,并告诉JVM调用run()方法

2、实现Runnable接口的类
步骤:
①定义一个类实现Runnable接口
②覆盖接口中的run()方法
③创建Thread类的对象
④将Runnable接口的子类对象作为参数传给Thread类的构造方法
⑤调用Thread类的start()方法开线程

3、实现Callable接口(泛型)有返回值
步骤:
①工厂类Executors静态方法newFixedThreadPool,来创建线程池对象
②线程池对象ExecutorService接口实现类,调用submit提交线程任务ExecutorService
示例:
ExecutorService ex = Executors.newFixedThreadPool(2);
Future submit = ex.submit(new CallableDemo());
String s=submit.get();//要抛出异常
System.out.println(s);

二、线程安全

1.定义

线程休眠后,可能会进入执行状态,也可能会进入受阻塞状态,此时线程就会出现安全隐患。

2.同步技术

为了解决线程安全问题,我们通常采用同步技术。

3.三种同步技术

①同步代码块
synchronized (任意对象){
线程要操作的共享数据
}//同步代码块
对象:同步锁
作用:保证安全,没有锁的线程不能执行
注意:线程在遇到同步代码块后,线程会判断同步锁还有没有,如果有,获取锁进入同步中,去执行代码,执行完毕后,除去同步代码块,线程再将锁还回去。没有锁的线程,不能进入同步。在同步中的线程不出去同步,不会释放锁。
②同步方法
public synchronized void med(){
共享数据
}
注意:同步方法也是有锁的,是本类对象引用(this)
③静态同步方法
public static synchronized void med(){
共享数据
}
注意:静态同步方法也有锁,但不是this,静态对象生命周期早,应是类名.class

4.死锁

      当线程任务中出现了多个同步时候,如果同步中嵌套了其他同步,这时候容易一种现象,程序会出现无限等待。

三、线程通信

这里用个例题简单体现线程通信在wait()和notify()上的应用。

1.题目

小明-男,小红-女,用线程来分别对这两个人的姓名和性别进行输入输出。

如图所示在这里插入图片描述

2.思路

1.先考虑建几个类
这里建4个:含有main方法的类、Resource类(存放姓名、年龄这两个成员变量)、以及输入输出两个线程
2.涉及到的思维
①用构造方法传参来防止输出为null值的情况
②同步代码块的运用来解决线程安全隐患
③同步代码块中的任意对象应为本类对象
④两个线程也应该用的是同一把锁
注:同步技术重点是同一把锁
⑤用标记flag来判断输入输出中线程的等待及唤醒状态
⑥Iuput类是输入赋值,判断flag值是否为true,是则表明赋值完成,则进行等待,若不是,则将flag值改为true,并唤醒另一个线程;Output类是取值,判断flag值是否为false,是则表明取值完成,则进行等待,若不是,则将flag值改为false,进行取值并唤醒另一个线程。

3.代码

1.main函数代码:

public class Test {
    public static void main(String[] args) {

        Resource r=new Resource();
        Input in=new Input(r);
        Output ou=new Output(r);
        Thread t0=new Thread(in);
        Thread t1=new Thread(ou);
        t0.start();
        t1.start();
    }

}

2.Resource类

public class Resource {
    public String name;
    public String sex;
    //做标记
    public boolean flag=true;
}

3.Iuput类

package Day24;

public class Input implements Runnable {
    private int i=0;
    Resource r;
    public Input(Resource r){
        this.r=r;
    }
    @Override
    public void run(){
        while (true){
            synchronized (r){
                if (r.flag){
                    try{r.wait();}catch(Exception ex){}
                }
            //这里对两个变量进行赋值
            if (i%2==0){
                 r.name="小明";
                 r.sex="男";
            }else {
                r.name="小红";
                r.sex="女";
            }
            r.flag=true;
                r.notify();
            i++;
            }
        }
    }
}

4.Output类

public class Output implements Runnable {
    Resource r;
    public Output(Resource r) {
        this.r=r;
    }
    @Override
    public void run(){
        while (true){

            synchronized (r){
                //判断标记,是false的话就等待
                if (!r.flag){
                    try{r.wait();}catch (Exception ex){}
                }
                System.out.println(r.name+"   "+r.sex);
                //唤醒对方线程
                r.flag=false;
                r.notify();

            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值