Java基础学习生疏知识点总结(18)——多线程(上)

1、操作系统相关知识

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

2、java程序运行

java命令启动java程序的原理

  • java命令,创建jvm进程
  • jvm进程创建一个线程,主线程 main
  • 执行主线程中的main方法

jvm是单线程还是多线程

  • jvm是多线程的,起码有一个垃圾回收线程

3、多线程的实现方式一:继承Thread

文档实例

Thread类线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
在这里插入图片描述
步骤

  1. 继承Thread类
  2. 重写里面的run方法
  3. 创建子类对象
  4. start方法去启动线程

示例:

public class Demo {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

// 启动线程
        myThread.start();
                }
}

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }
}

获取设置线程名称

  • 获取 getName()

    • 默认线程名 Thread-0 类名+数字
  • 设置 setName()

  • Thread(String name) 分配新的 Thread 对象。

如何获取主线程的名称
在这里插入图片描述

public class Demo1 {
    public static void main(String[] args) {
        // static Thread currentThread()
        // 返回对当前正在执行的线程对象的引用。
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
        MyThread myThread = new MyThread("吴彦祖");
        myThread.start();
    }
}

class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}

在这里插入图片描述
注意事项

  • 一个Thread或Thread子类对象才代表一个线程
  • 为什么要重写run方法?
    • 只有Thread中的run方法中代码才会在子线程中执行
    • 为了保证子线程中运行的是我们的想要他执行的代码,我们要重写run方法(换句话说,把我们想要在子线程中执行的任务封装在了run方法中)
  • 一个方法,被哪个线程调用,这个方法就运行在调用它的那个线程当中
  • 启动线程,必须要用start方法而不是run方法。如果只是线程对象.run() 那么这仅仅只是普通方法调用。
  • 同一个Thread对象或子类对象只能被启动一次。如果我想启动多个线程的话,只能创建多个对象IllegalThreadStateException

4、线程调度方式

两种调度方式

线程调度是指系统为线程分配处理器使用权的过程。
调度的方式主要有两种:

  1. 协同式线程调度。
    a. 如果使用协同式调度的多线程系统,线程的执行时间,由线程本身来控制,线程把自己的工作执行完了之后
    主动通知系统切换到另外一个线程上去。

    b. 其最大的好处是实现简单,坏处是线程执行时间不可控

  2. 抢占式线程调度
    a. 如果使用抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身决定。
    b. 其最大的好处是,线程的执行时间是可控的

java中采用的是抢占式线程调度方式

5、线程优先级

操作系统的线程调度

  • 静态优先级+动态优先级
  • 正在CPU上执行的线程会随着执行时间的延长而降低优先级,等待的线程会随着等待的时间的延长优先级而升高

获取 设置优先级

  • get 和 set方法
public class Demo2 {
    public static void main(String[] args) {
        MyThread2 t1 = new MyThread2();
        MyThread2 t2 = new MyThread2();
        t1.setName("短风");
        t2.setName("细风");
        // 设置线程优先级 线程优先级的范围1-10
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        // 获取优先级
        // 默认优先级 5
        int priority = t1.getPriority();
        System.out.println(priority);
        int priority2 = t2.getPriority();
        System.out.println(priority2);
    }
}

class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"----"+i);
        }
    }
}

为什么大的优先级没有先执行?
我们设置的优先级是静态优先级,仅仅只是给操作系统的一种建议.
java官方: 线程优先级并非完全没有用,我们Thread的优先级,它具有统计意义,总的来说,高优先级的线程占用的cpu执行时间多一点,低优先级线程,占用cpu执行时间,短一点

6、线程控制API

6.1 休眠线程sleep

public class SleepThreadDemo {
    public static void main(String[] args) {
        SleepThread t = new SleepThread();

        t.start();
    }
}

class SleepThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"---"+i);
            try {
                //Thread.sleep(2000);
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

6.2 合并线程join

2个问题

  • 谁等待:调用join的代码在哪个线程中运行就是哪个线程等待
  • 等待谁:等待调用join的那个线程
    在这里插入图片描述
public class JoinThreadDemo {
    public static void main(String[] args) {
        System.out.println("main start");
        JoinThread joinThread = new JoinThread();
        joinThread.setName("55开");
        joinThread.start();
        try {
            joinThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main end");
    }
}

class JoinThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"----"+i);
        }
    }
}

6.3 守护进程daemon

分类:

  • 用户线程
  • 守护线程

setDaemon(boolean on) 将该线程标记为守护线程或用户线程。

注意;

将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。

该方法必须在启动线程前调用。

java.lang.IllegalThreadStateException:启动线程之后调用

6.4 礼让线程yield

static voidyield() 暂停当前正在执行的线程对象,并执行其他线程。
public class YieldThreadDemo {
    public static void main(String[] args) {
        YieldThread t1 = new YieldThread();
        YieldThread t2 = new YieldThread();

        t1.setName("金牌讲师");
        t2.setName("粤港澳第一赌神");

        t1.start();
        t2.start();


    }
}

class YieldThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"----"+i);
            // yield() 暂停当前正在执行的线程对象,并执行其他线程。
            Thread.yield();
            // 为什么没有你一个我一个的执行呢?
            // 虽然调用了yield方法,放弃CPU的执行权,但是java采用的是抢占式调度方式
            // 仍然会参加下一轮的CPU竞争 并不能保证一定保证被哪个线程抢到执行权.
        }
    }
}

6.5 中断线程stop,interrupt

练习:
安全的终止线程

提示: 用flag标记 如果为true 正常执行 如果为false 终止线程执行

在终止之前,去做一个日志保存 , 将终止信息保存到log.txt当中

利用FileWriter , 2021-4-28 时分秒 : 某个线程 终止了

public class SecurityStopDemo {
    public static void main(String[] args) {
        StopThread2 stopThread2 = new StopThread2();
        stopThread2.setName("张三");
        stopThread2.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stopThread2.flag = false;
    }
}

class StopThread2 extends Thread {
    boolean flag = true;
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (flag) {
                System.out.println(getName() + "----" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();

                }
            } else {

                // flag 为 false说明线程终止
                System.out.println("线程终止");
                // 记录哪个线程 什么时间发生了中断
                try {
                    FileWriter fileWriter =
                            new FileWriter("../day19_thread02/log.txt");
                    SimpleDateFormat simpleDateFormat =
                            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String formatTime = simpleDateFormat.format(new Date());
                    String s = formatTime + ": " + getName() + " 发生了中断,数据已保存";
                    fileWriter.write(s);
                    fileWriter.write(System.lineSeparator());
                    fileWriter.flush();
                    fileWriter.close();
                    
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // 进行一些数据保存的操作
                return;
            }
        }

interrupt
如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

public class InterruptThreadDemo {
    public static void main(String[] args) {
        StopThread3 stopThread3 = new StopThread3();
        stopThread3.setName("女流");
        stopThread3.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 抛出中断异常 相当于泼了一盆冷水
        stopThread3.interrupt();

    }
}

class StopThread3 extends Thread {
    @Override
    public void run() {
        System.out.println("stop before");
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"----"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("有异常");
            }
        }
        System.out.println("stop end");
    }
}

stop

public class ThreadStopDemo {
    public static void main(String[] args) {
        ThreadStop threadStop = new ThreadStop();
        threadStop.setName("短风");
        threadStop.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 会终止线程执行
        threadStop.stop();
    }
}
class ThreadStop extends Thread{
    @Override
    public void run() {
        System.out.println("ThreadStop start");
        for (int i = 0; i <10; i++) {
            System.out.println(getName()+"-----"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("ThreadStop end");
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值