【JavaSE---13】线程

1. 线程

  1. 定义多线程类:
    1. 继承Thread类,并重写run方法。
    2. 实现Runnable接口,并重写run方法。【推荐使用】

    注意:

    1. Thread类实现了Runnable接口。
    2. 由于Java是单继承机制,若要变为多线程的类已经继承了其他类,那么其只能使用第二种方法,即继承Runnable接口。
  2. 主线程与子线程:CPU调度的最小单位为线程,故一个进程至少包含一个线程。运行java程序形成的进程也至少包含一个线程,这个线程又叫主线程。主线程执行的内容为public static void main(String[] args) { }中的内容。
    1. 创建子线程语法:
      1. 若采用继承Thread类,则:
        在这里插入图片描述
      2. 若采用实现Runnable接口,则:
        在这里插入图片描述

      注意:不能直接调run方法,因为run方法没有开启线程的功能。

    2. 主线程不会阻塞,子线程会阻塞。
      在这里插入图片描述
  3. 同一线程对象开启多个线程:
    1. 好处:由同一个线程对象所开启的线程不仅共享静态属性,还共享其普通属性
      在这里插入图片描述
    2. 语法:
      在这里插入图片描述
    3. 一个售票系统的例子:
      在这里插入图片描述
  4. 线程结束
    1. 子线程中无while循环,则不可随时结束此线程,只能执行完后自然结束。
    2. 子线程中有while循环,则可以随时结束此线程。实现步骤:
      ① 在多线程类中定义一个boolean类型的属性。
      ② 将该属性作为循环条件。
      ③ 主线程采用通知方式修改该属性值。
      在这里插入图片描述
  5. 用户线程 与 守护线程
    1. 用户线程 / 工作线程:当线程任务执行完(无while)采用通知方式结束(有while),线程才会结束。
    2. 守护线程:只有当所有的用户线程结束后,守护线程才结束。如:垃圾回收机制。
      1. 默认情况下,一个线程的结束不会影响其他线程的结束,且当所有线程结束后,进程才结束。
      2. 若要实现功能:主线程结束,则所有子线程结束。则可以将所有子线程设置为守护线程。
        语法为:
        在这里插入图片描述
  6. 线程编程规律:
    1. 若有几个功能需要并发的执行,则必须使用线程。因为进程是一行一行的代码执行,不能实现并发。
    2. 多个功能不相同的线程,则一个类编写一个功能。
      多个功能相同的线程,则只需编写一个类,使用一个实例化线程对象开启多个线程。

练习:
在这里插入图片描述
分析:
在这里插入图片描述
代码:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        AA aa = new AA();
        BB bb = new BB(aa);
        new Thread(aa).start();
        new Thread(bb).start();
    }
}

class AA implements Runnable {
    private boolean isLoop = true; // 以便其他线程采用通知方式关闭此线程
    @Override
    public void run() {
        while (isLoop) {
            System.out.println((int) (Math.random() * 100));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void setLoop(boolean loop) {
        isLoop = loop;
    }
}

class BB implements Runnable {

    private AA aa;
    private Scanner input = new Scanner(System.in);

    public BB(AA aa) {
        this.aa = aa;
    }

    @Override
    public void run() {
        while (true) {
            char c = input.next().charAt(0);
            if ('Q' == c) {
                aa.setLoop(false); // 通知AA线程结束
                break;
            }
        }
    }
}

2. Thread类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3. 线程七大状态

在这里插入图片描述

4. 线程同步

  1. 线程同步:指在多线程中,对于线程的共享数据,保证该数据在任何时刻最多只有一个线程访问,保证数据的完整性。
    【即 互斥的请求某种共享资源】
  2. 实现线程同步:
    1. 非静态:互斥锁为共享的同一对象
      1. 同步普通方法:默认互斥锁为:当前对象this
        在这里插入图片描述
      2. 同步代码块,且该语句在普通方法内:互斥锁为:传入的对象
        在这里插入图片描述
    2. 静态:互斥锁同一类.class
      1. 同步静态方法:默认互斥锁为:所在线程类.class
        在这里插入图片描述
      2. 同步代码块,且此语句在静态方法内:互斥锁为:传入的类.class
        在这里插入图片描述

    小结:判断是否实现线程的核心:互斥锁是否为共享的同一对象同一类.class,即是否是同一把锁
    在这里插入图片描述
    练习:
    在这里插入图片描述

import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // 实例化两个人
        Person p1 = new Person("张三");
        Person p2 = new Person("李四");
        // 两个人并发的不断取钱
        new Thread(new Card(p1)).start();
        new Thread(new Card(p2)).start();
    }
}

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Card implements Runnable {
    private static double money = 1000; // 卡的金额
    private static boolean isLoop = true; // 用于控制是否循环取钱
    private Person person;

    public Card(Person person) {
        this.person = person;
    }

    // 因为实例化两个线程对象,而互斥锁必须为共享的对象或类.class。我选择了用static
    public static synchronized boolean outMoney(Person person, double oMoney) {
        // 是否有钱取
        if (money <= 0) {
            System.out.println("余额为0,终止取钱");
            isLoop = false;
            return false;
        }
        if (money < oMoney) {
            System.out.println("余额不足,此次取钱失败!");
            return false;
        }
        // 取钱
        money -= oMoney;
        System.out.println(person.getName() + "取钱成功!此次取钱" + oMoney + "元,还剩" + money + "元");
        return true;
    }

    @Override
    public void run() {
        // 不断的取钱
        while (isLoop) {
            outMoney(person, 100); // 每次取 100元
            // 休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

5. 线程死锁

import java.util.Objects;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        AA aa1 = new AA(1);
        AA aa2 = new AA(2);
        new Thread(aa1).start();
        new Thread(aa2).start();
    }
}

class AA implements Runnable {
    private static Object o1 = new Object(); // 第一种资源的锁
    private static Object o2 = new Object(); // 第二种资源的锁
    private int resourceType = 1; // 1表示第一种资源;2表示第二种资源

    public AA(int resourceType) {
        this.resourceType = resourceType;
    }

    @Override
    public void run() {
        if (1 == resourceType) {
            synchronized (o1) { // 互斥的请求第一种资源
                System.out.println(Thread.currentThread().getName() + "进入1");
                synchronized (o2) { // 互斥的请求第二种资源
                    System.out.println(Thread.currentThread().getName() + "进入2");
                }
            }
        } else if (2 == resourceType) {
            synchronized (o2) { // 互斥的请求第二种资源
                System.out.println(Thread.currentThread().getName() + "进入3");
                synchronized (o1) { // 互斥的请求第一种资源
                    System.out.println(Thread.currentThread().getName() + "进入4");
                }
            }
        }
    }
}

输出:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ElegantCodingWH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值