JavaSE进阶598-620 多线程(一) 线程/进程/线程方法

开始时间:2021-01-05

进程和线程

4.1、什么是进程?什么是线程?
进程是一个应用程序(1个进程是一个软件) .线程是一个进程中的执行场景/执行单元-
一个进程可以启动多个线程。
4.2、对于java程序来说,当在Dos命令窗口中输入;
java Helloworld回车之后-
会先启动JVM,而JVM就是一个进程。JVM再启动一个主线程调用main方法。
同时再启动一个垃圾回收线程负责看护,回收垃圾。最起码,现在的java程序中至少有两个线程并发,
一个是垃圾回收线程,一个是执行main方法的主线程。

4.3、进程和线程是什么关系?举个例子
阿里巴巴:进程
马云:阿里巴巴的一个线程童文红:阿里巴巴的一个线程京东:进程
强东:京东的一个线程妹妹:京东的一个线程
进程可以看做是现实生活当中的公司.线程可以看做是公司当中的某个员工。

注意:
进程A和进程B的内存独立不共享。
线程A和线程B呢?
在java语言中:
线程A和线程B,堆内存和方法区内存共享。但是栈内存独立,一个线程一个栈。

Java虚拟机中,堆和方法区只有一个,栈可以有多个,多个栈就是多线程。
启动10个线程,就会有10个栈空间,互不干扰->多线程并发(提高效率)
火车站:进程
每个售票窗口:线程

使用了多线程后,main方法结束,可能程序也没有结束。只是主线程结束。
主栈空了,其他栈可能还在压栈弹栈

判断

package BUPT20210106;

public class ThreadTest01 {
    public static void main(String[] args) {
        System.out.println("main begin!");
        m1();
        System.out.println("main over!");
    }

    private static void m1() {
        System.out.println("m1 begin!");
        m2();
        System.out.println("m1 over!");
    }

    private static void m2() {
        System.out.println("m2 begin!");
        System.out.println("m2 over!");
    }
}

只有一个main线程

多线程启用示例1

编写一个类,直接继承Thread,重写run方法

package BUPT20210106;

/*
实现线程的方法1
直接继承Java.lang.Thread,重写run方法
 */
public class ThreadTest02 {
    public static void main(String[] args) {
//新建一个线程对象
        MyThread myThread = new MyThread();

        //myThread.run();//不启动线程,不会分配新的分支栈,跟调用普通程序没两样
        //启动线程
        //start的作用。启动线程,在JVM中开辟一个新的栈空间
        //开启栈空间后,start方法就结束了,启动的线程会自动调用run方法
        //分支和主同时工作,不过还是有个先后,每次输出有个多少的差异,不会同时结束
        //因为控制台只有一个,某个线程会先抢到执行权
        myThread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程->" + i);
        }
    }
}

class MyThread extends Thread {
    public void run() {
        //分支线程中
        for (int i = 0; i < 100; i++) {
            System.out.println("分支线程->" + i);
        }
    }
}

多线程启动示例2

编写一个类,实现Java.lang.Runnable接口,实现run方法

package BUPT20210106;

public class ThreadTest03 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Myrunnable());
        thread.start();
        for (int i = 0; i < 120; i++) {
            System.out.println("主线程->" + i);
        }
    }
}

//可运行类,还不是一个线程
class Myrunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("分支线程->" + i);
        }
    }
}


使用匿名内部类

参考内部类
内部类二

package BUPT20210106;

/*
匿名内部类
 */
public class ThreadTest04 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("分支线程->" + i);
                }
            }
        });
        t.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程->" + i);
        }
    }
}

线程生命周期

在这里插入图片描述

获取线程的名字

package BUPT20210106;

/*
获取当前线程对象
 */
public class ThreadTest05 {
    public static void main(String[] args) {
        MyThread1 myThread = new MyThread1();
        //修改线程的名字,如果不修改 默认为 Thread-0
        myThread.setName("ttt");
        //获取线程的名字
        String name = myThread.getName();
        System.out.println(name);
        myThread.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程" + i);
        }
    }
}

class MyThread1 extends Thread {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("分支线程" + i);
        }
    }
}
package BUPT20210106;

/*
获取当前线程对象
 */
public class ThreadTest05 {
    //也在主线程里面
    public void doSome() {
        //不行
        //this.getName();
        //super.getName();
        //可以获取当前线程名字
        System.out.println("doSome"+Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ThreadTest05 tt = new ThreadTest05();
        tt.doSome();
        Thread currentThread = Thread.currentThread();
        System.out.println(currentThread.getName());
        MyThread1 myThread = new MyThread1();
        //修改线程的名字,如果不修改 默认为 Thread-0
        myThread.setName("ttt");
        //获取线程的名字
        myThread.start();
        for (int i = 0; i < 200; i++) {
            System.out.println(currentThread.getName() + "->" + i);
        }
    }
}

class MyThread1 extends Thread {
    public void run() {
        for (int i = 0; i < 100; i++) {
            Thread currentThread = Thread.currentThread();
            System.out.println(currentThread.getName() + "->" + i);
            //super和this在这里都可以,但是对于其他情况不一定适用的,只是因为这个地方写在了类里面
            System.out.println(this.getName() + "--" + i);
            System.out.println(super.getName() + "-" + i);
        }
    }
}

线程的sleep方法

可以作为定时器,每次遇到Thread.sleep,就会进入阻塞阶段
间隔特定时间,执行特定代码

package BUPT20210106;

public class ThreadTest06 {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);
            Thread.sleep(1000 * 2);
        }
    }
}

sleep面试题

该程序是否能让分支线程进入睡眠?

package BUPT20210106;

public class ThreadTest07 {
    public static void main(String[] args) throws InterruptedException {
        MyThread3 myThread3 = new MyThread3();
        myThread3.setName("t3");
        myThread3.start();
        //调用sleep方法,但这个程序不会进入休眠状态
        //sleep是静态方法,执行的时候还是会转为Thread.sleep
        //让当前线程进入休眠,即main方法进入睡眠
        //3秒后才输出hello world,myThread3并没有睡
        myThread3.sleep(1000*3);
        System.out.println("hello world!");
    }
}

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

中止睡眠

package BUPT20210106;

/*
唤醒正在睡眠的线程
这并不是终止线程的执行,
 */
public class ThreadTest08 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Myrunnable2());
        thread.setName("t");
        thread.start();
        //希望五秒后,t线程醒来
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止t线程的睡眠,干扰,通过报Java异常处理机制进行中断
        thread.interrupt();

    }
}

class Myrunnable2 implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "->begin");
        //这里只能try catch不能抛异常
        //因为子类重写不能抛出比父类更多的异常
        try {
            //睡一天
            Thread.sleep(1000 * 60 * 60 * 24);
        } catch (InterruptedException e) {
            //打印异常信息
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "->end");
    }
}

输出

t->begin
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at BUPT20210106.Myrunnable2.run(ThreadTest08.java:33)
	at java.base/java.lang.Thread.run(Thread.java:832)
t->end

强制终止线程

package BUPT20210106;

/*
强行终止线程
 */
public class ThreadTest09 {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable3());
        thread.setName("t");
        thread.start();
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //5秒后强行终止t线程
        thread.stop();//过时用法,示例用一用,容易丢数据
    }
}

class MyRunnable3 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

合理终止线程执行

通过修改标记来执行

package BUPT20210107;

public class ThreadTest10 {

    public static void main(String[] args) {
        MyRunnable4 myRunnable4 = new MyRunnable4();
        Thread t = new Thread(myRunnable4);
        t.setName("tt");
        t.start();
        //模拟5秒
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止t的执行
        myRunnable4.run = false;
    }
}

class MyRunnable4 implements Runnable {
    //做一个布尔标记
    boolean run = true;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (run) {
                System.out.println(Thread.currentThread().getName() + "->" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                //终止当前线程
                return;
            }
        }
    }
}

线程调度模型

常见的线程调度模型有哪些?

  • 抢占式调度模型:
    哪个线程的优先级比较高,抢到的CPU时间片的概宰就高一些/多一些。Java采用的就是抢占式调度模型。
  • 均分式调度模型:
    平均分配CPU时间片。每个线程占有的cPu时间片时间长度一样。平均分配,一切平等。

线程调度方法

1.2、java中提供了哪些方法是和线程调度有关系的呢?

  • 实例方法:
    void setPriority(int newPriority)设置线程的优先级int getPriority(获取线程优先级
    最低优先级1
    默认优先级是5最高优先级10
    优先级比较高的获取cPu时间片可能会多一些。(但也不完全是,大概率是多的.)
  • 静态方法:
    static void yield让位方法
    暂停当前正在执行的线程对象,并执行其他线程
    yield()方法不是阻塞方法。让当前线程让位,让给其它线程使用。yield()方法的执行会让当前线程从"运行状态"回到"就绪状态". 回到就绪后还可以再去参与抢占过程,和阻塞不一样

线程的优先级

package BUPT20210107;

/*
关于线程的优先级,优先级较高的,抢CPU时间片相对多一些
 */
public class ThreadTest11 {
    public static void main(String[] args) {
        System.out.println("最高优先级" + Thread.MAX_PRIORITY);//最高为10
        System.out.println("最低优先级" + Thread.MIN_PRIORITY);//最低为1
        System.out.println("默认优先级" + Thread.NORM_PRIORITY);//默认为5
        Thread currentThread = new Thread();
        //默认为5
        System.out.println(currentThread.getPriority());
    }
}

人为可以设置优先级

package BUPT20210107;

/*
关于线程的优先级,优先级较高的,抢CPU时间片相对多一些
 */
public class ThreadTest11 {
    public static void main(String[] args) {
        //当前线程为主线程
        Thread.currentThread().setPriority(1);
        Thread currentThread = Thread.currentThread();
        Thread t = new Thread(new MyRunnable5());
        //t线程设置为10
        t.setPriority(10);
        t.setName("t");
        t.start();
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);
        }
    }
}

class MyRunnable5 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);

        }
    }
}

观察结果可以发现设置了优先级更高的t抢得更快

线程让位

package BUPT20210107;

/*
当前线程暂停,回到就绪状态,让给其他线程
静态方法 Thread.yield()
 */
public class ThreadTest12 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable6());
        t.setName("t");
        t.setPriority(10);
        t.start();
        for (int i = 1; i <= 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);
        }
    }
}

class MyRunnable6 implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            if (i % 100 == 0) {
                Thread.yield();//100的倍数,当前线程暂停一下,让给主线程
            }
            System.out.println(Thread.currentThread().getName() + "->" + i);
        }
    }
}

线程合并

package BUPT20210106;

/*
线程合并
 */

public class ThreadTest13 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("main begin!");
        Thread thread = new Thread(new MyRunnable7());
        thread.setName("t");
        thread.start();
        //栈之间进行协调
        thread.join();//Thread合并到当前线程中,当前线程受阻塞,Thread线程执行直到结束
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "->" + i);
        }
        System.out.println("main over!");
    }
}

class MyRunnable7 implements Runnable {

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

2021-01-07

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值