进程

相关概念

  1. 是正在运行的程序
  2. 是系统进行资源分配和调用的独立单位
  3. 每个进程都游它自己的内存空间和系统资源

线程

相关概念

  1. 是进程中的单个顺序控制流,是一条执行路径
  2. 单线程:一个进程中只有一条执行路径,称为单线程程序
  3. 多线程:一个进程中有多条执行路径,称为多线程程序

JAVA中的线程调度模型

抢占式调度模型:各个线程抢占cpu时间片,抢到时间片线程才可正常运行。优先级高的抢到时间片的概率大

多线程的实现方式一(继承Thread类)

  1. 自定义一个类继承Thread类
  2. 在类中重写Thread类中的run()方法,方法体为线程执行的代码
public class MyThreadDemo extends Thread {
    //声明有参构造,方便在创建对象时直接设定线程名称

    public MyThreadDemo(String name) {
        super(name);//此语句访问了父类Thread的有参构造,以name作为有参构造参数传递,此时name即为线程名
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //直接调用Thread中的getName()方法获取线程名称
            System.out.println(getName()+":"+i);
        }
    }


}
  1. 创建类对象
  2. 调用继承自Thread类中的start()方法启动线程
MyThreadDemo mtd=new MyThreadDemo("aaa");//直接创建线程名为aaa的线程对象mtd
        MyThreadDemo mtd2=new MyThreadDemo("bbb");//直接创建线程名为bbb的线程对象mtd2
        mtd.start();//启动线程
        mtd2.start();

注意点:
启动线程的步骤

  1. 调用statrt()方法
  2. JVM会调用此线程中重写的run()方法

若直接调用重写后的run()方法,线程不会启动,只会单纯执行该类run()方法调用

Thread类中的常用方法

1.设置线程名称:void setName(String name)

MyThreadDemo mtd=new MyThreadDemo("aaa");//直接创建线程名为aaa的线程对象mtd
mtd.setName("线程1");//原线程名为aaa修改为线程1

2.获取线程对象的线程名称:String getName

MyThreadDemo mtd=new MyThreadDemo("aaa");//直接创建线程名为aaa的线程对象mtd
String str=mtd.getName();
System.out.println(str);//结果为aaa

3.获取当前正在执行的线程对象: static Thread currentThread()

4.获取线程的优先级: int getPriority() 默认线程优先级为5
5.设置线程的优先级:void setPriority(int newPriority) 线程优先级范围为1~10,10最高
**注意点:**线程优先级越高只是代表抢占到cpu时间片的概率越大,并非是一定比优先级低的线程先运行

线程控制(Thread类中方法)

1.static void sleep(long millis): 使当前正在执行的线程对象暂停执行指定参数的毫秒数,暂停时间结束后继续执行

@Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //直接调用Thread中的getName()方法获取线程名称
            System.out.println(getName()+":"+i);
            Thread.sleep(1000);//线程每输出一次就会暂停1s
        }

2.void join:等待线程死亡,若有线程对象调用此方法,那么其他线程必须等待此线程结束,才能运行

ThreadJoin one =new ThreadJoin("飞机");
        ThreadJoin two =new ThreadJoin("高铁");
        ThreadJoin three =new ThreadJoin("自行车");
        //调用join()使得线程对象one先死亡,后其余两个线程才能开始执行
        one.start();
        one.join();
        two.start();
        three.start();

注意点: 线程对象调用join()方法必须在线程已经调用start()方法的情况才有效

3.void setDaemon(boolean on):将线程设置为守护线程,当运行的线程都是守护线程时,JAVA虚拟机将会退出(但不会立即推出,守护线程仍会运行一小段时间)当参数为true表示设置为守护线程

线程的生命周期

java 等待多线程执行结束后执行 java多线程执行一半不动_java 等待多线程执行结束后执行

多线程的实现方式二(实现Runnable接口)

  1. 自定义一个类实现Runnable接口
  2. 在类中重写run()方法,方法体为线程执行的代码
//创建自定义类,该类要实现Runnable接口
public class RynnableDemo implements Runnable {

//重写Runnable中的run()方法
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

3.创建自定义类对象
4.以自定义类对象作为参数,创建Thread类对象
5.调用start()方法启动线程

//创建实现Runnable接口的自定义类对象
        RynnableDemo rd=new RynnableDemo();
    
        //可采用有参构造方式,直接声明线程的名称
        Thread t=new Thread(rd,"666");
        //启动线程
        t.start();

相比于继承Thread类实现多线程的优点

  1. 避免了Java单继承的局限性
  2. 适合多个相同程序的代码取处理同一个资源的情况,把线程和程序的代码、数据有效分离较好的体现了面向对象的设计思想

多线程程序数据安全问题

数据安全问题判断标准
  1. 是否为多线程
  2. 是否有共享数据(一般指自定义的成员变量)
  3. 多条语句操作共享数据
    以上标准全部满足才会发生数据安全问题
解决方法

基本思想: 让程序没有安全问题的环境,一般针对多条语句操作共享数据进行解决

**如何实现:**把多条语句操作共享数据的代码给”锁“起来,让任意时刻只能由一个线程执行

“锁”的方法1.:同步代码块关键字synchronized

Object obj=new Object()
 // synchronized (obj) {
 多条语句操作共享数据代码;
 }

“锁”的方法2.:同步方法关键字synchronized此时锁的对象为this
“锁”的方法3.:同步静态方法关键字synchronized此时锁的对象为“类名.class”