Java十分钟入门多线程中篇

目录
  • 1、线程的调度:
    • 1、设置优先级(Priority):
    • 2、休眠(sleep)
    • 3、强制运行(join)
    • 4、礼让(yield)
  • 2、定时器线程:
  • 3、线程的同步:

举例说明:

我们知道飞机在天上飞行是有固定的航线(可以理解成线程),每个机场都有最大的运行负载能力,当运行情况超过了负载能力的时候,这就需要塔台调度参与,会根据每架飞机的优先级排序。当在航线的时候,如果出现紧急情况,会让其他飞机避让,让这架飞机优先级提高,先降落。这就是调度,计算机程序线程运行也是这样的。

1、线程的调度:

在Java多线程中,主要可以通过下面四个方法来分配CPU的使用权:

  • 设置优先级(Priority) 设置线程的优先级,值是1-10
  • 休眠(sleep) 单位毫秒,让本线程属于阻塞状态,CPU会执行其他线程
  • 强制运行(join) 让这个线程强制获取CPU资源来运行
  • 礼让(yield) 暂停正在执行的线程,让其他线程先执行,执行完了在接着执行

1、设置优先级(Priority):

有两个线程,分别设置最大优先级和最小优先级:

public class MyThread implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"正在运行:"+i);
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread(),"线程A:");
        Thread t2 = new Thread(new MyThread(),"线程B***:");

        //设置优先级: 最高为10  最低为1
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);

        //显示线程优先级:
        System.out.println("线程A的优先级是:"+t1.getPriority());
        System.out.println("线程B的优先级是:"+t2.getPriority());

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

结果:

2、休眠(sleep)

Thread.sleep();--------单位是毫秒,让本线程属于阻塞状态,CPU会执行其他线程:

public class ThreadSleep {
    public static void main(String[] args) {
        sleepTime(5);
    }

    private static void sleepTime(int time) {
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行了:"+i+"s");
            try{
                //让线程休眠,进入阻塞状态
                Thread.sleep(1000); //休眠时间为1000毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

3、强制运行(join)

顾名思义,就是让某个线程强制进入执行:

子线程:

public class MyThread {
}

测试类:

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

        Thread t1=  new Thread(new MyThread(),"我是子线程");
        t1.start();
        //当主线程执行任务1-10时,如果执行到5就让子线程t1强制进来执行,直到执行完了才让主线程继续执行任务
        for (int i = 0; i < 6; i++) {
            if (i==2){
                t1.join();
            }
            System.out.println(Thread.currentThread().getName()+"正在运行:"+i);
        }
    }
}

结果:

4、礼让(yield)

暂停正在执行的线程,让其他线程先执行,执行完了在接着执行:

public class MyThread implements Runnable{

    //线程礼让,让本线线程阻塞,其他线程先执行
    //这里就是A线程运行二次后,礼让,让B 线程先执行
    //也是理论上的,就是不管怎么样第二次后面肯定让B先执行,但是后面就随机了
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"正在运行:"+i);
            if(i == 2){
                Thread.yield();
            }
        }
    }
}

测试类:

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

        Thread t1 = new Thread(new MyThread(),"线程A:");
        Thread t2 = new Thread(new MyThread(),"----线程B");

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

结果:

2、定时器线程:

定时器就是可以设置某个时间点来执行某个事件,比如系统每周删除依次日志文件,或者在指定的日期关闭系统,定时器本身就是一个线程任务来在指定的时候执行该任务。定时器是继承TimerTask来重写run方法,专门处理定时任务。

演示Demo:

public class MyThread extends TimerTask {

    @Override
    public void run() {
        //把任务定义在run方法中
        showMyself();
    }

    public void showMyself(){
        System.out.println("被Run方法执行的");
    }
}

测试类:

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

        Timer timer = new Timer();

        //设置5秒后执行这个任务,并且每1秒重复执行这个任务

        timer.schedule(new MyThread(),5000,1000);

    }
}

结果:

3、线程的同步:

首先我们先看一个demo:

创建了两个线程对象,一个线程A任务用于执行print1,另一个线程B任务用于执行print2:

    public void print1(){
        System.out.print("中");
        System.out.println("国");
    }

    public void print2(){
        System.out.print("浙");
        System.out.println("江");
    }
}

测试类:

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

        Printer p = new Printer();
        //A:
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    p.print1();
                }
            }
        },"线程A:").start();

        //B:
        new Thread("线程B:"){
            @Override
            public void run(){
                while (true){
                    p.print2();
                }
            }
        }.start();
    }
}

这个程序就是当线程A执行的时候,输出中国,当B执行的时候,输出浙江,理论上是没有任何问题,但是我们看一下结果:

我们发现出问题了,其实这就是非线程同步(异步):

  • 同步:提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事
  • 异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

其实非线程同步在有些系统是很危险的问题,比如12306,如果使用非线程同步,那么后果可想而知,那么该如何同步呢? 这里介绍一个常用的方法,就是上锁:

如果两端代码(两个线程任务)是同步的,那么CPU同一时间只能执行一个任务,相当于给该线程上了一把锁, 在该线程没有执行完这段代码或者任务的时候,其他线程是不能占用CPU资源执行任务的。直到执行完了该线 程的代码,其他线程才可以执行。

更好的理解(举例):

你去公共厕所上厕所(大的),当你进去后,需要把门关上并锁着,这就是上锁,为了保证你正常的结束(保证线程正常运行完),这期间其他人是不能进来的。

Synchronized 锁:

两个线程任务使用同一个对象为锁,那么两个线程方法是同步的 我们把上面的方法上个锁:

class Demo {
}

public class Printer {

   //创建任意一个对象,只要是对象相同就是锁相同,就是同步的!
    Demo d = new Demo();  

    public void print1(){
    	//当进入print1这个方法时,synchronized就给这个方法上了一个锁
        synchronized (d){
            System.out.print("中");
            System.out.println("国");
        }
    }

    public void print2(){
        //当进入print2这个方法时,synchronized也给这个方法上了一个锁
        synchronized (d){
            System.out.print("浙");
            System.out.println("江");
        }
    }

}

这样输出后就不会出现上面的那个问题,这里就不发结果截图啦。大家可以自己试一试,看看是否解决了这个问题~

我们还可以把锁直接定义在方法上,比如这样子:

    public static synchronized void print1(){
            System.out.print("中");
            System.out.println("国");
    }

如果是静态方法,上锁的方式是通过.class字节码对象:

    public static void print1() {
        synchronized (Printer.class) {
            System.out.print("中");
            System.out.println("国");
        }
    }

小结: 这篇文章主要介绍了线程的调度(四种)、线程的定时以及线程的同步,内容也不少,多线程是Java的一个难点,也没用一些华丽的图片来演示,在学习过程中会比较枯燥,包括我自己也是。大家也可以看看视频,加深理解和印象!

到此这篇关于Java十分钟入门多线程中篇的文章就介绍到这了,更多相关Java 多线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一篇文章带你Java多线程入门

    目录 多线程的四种创建方式 1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 4.使用线程池 线程的优先级 测试Thread中常用的方法 线程的生命周期 多线程的同步控制 1.同步代码块 2.同步方法 3.同步锁 线程通信 wait/notify模式 sleep和wait的异同 总结 多线程的四种创建方式 1.继承Thread类 /* * 多线程的创建,方式一:继承Thread类 * 1.创建一个继承于Thread类的子类 * 2,重写Thread类的run()

  • 聊聊java多线程创建方式及线程安全问题

    什么是线程 线程被称为轻量级进程,是程序执行的最小单位,它是指在程序执行过程中,能够执行代码的一个执行单位.每个程序程序都至少有一个线程,也即是程序本身. 线程的状态 新建(New):创建后尚未启动的线程处于这种状态 运行(Runable):Runable包括了操作系统线程状态的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间. 等待(Wating):处于这种状态的线程不会被分配CPU执行时间.等待状态又分为无限期等待和有限期等待,处于无

  • 高价值Java多线程面试题分析

    问题一 A线程正在执行一个对象中的同步方法,B线程是否可以同时执行同一个对象中的非同步方法? 可以,两个线程运行所需资源不同,不需要抢占. 案例一. package duoxiancheng2; /** * @author yeqv * @program A2 * @Classname Ms1 * @Date 2022/2/7 19:08 * @Email w16638771062@163.com */ public class Ms1 { //A线程正在执行一个对象中的同步方法,B线程是否可以

  • Java十分钟入门多线程上篇

    什么是多线程? 在学习前,我们先对程序.进程.线程.并行.并发有个基础的概念了解: 程序: 为完成指定任务,用编程语言编写的一组指令的集合,即指一段静态的代码,静态对象. 进程: 是程序的一次执行过程,是一个动态的过程,进程自身有产生.使用和消亡的过程.(也称为生命周期,在后面会介绍) 线程: 进程可进一步细化为线程,是一个程序内部的一条执行路径,也就是进程内有线程 并行: 指两个或者多个事件在同一时刻发生,(同时发生) 并发: 指两个或者多个事件在同一个时段内发生,(并不是同时发生) 更好的理

  • Java多线程之线程安全问题详解

    目录 1.什么是线程安全和线程不安全? 2.自增运算为什么不是线程安全的? 3.临界区资源和竞态条件 总结: 面试题: 什么是线程安全和线程不安全? 自增运算是不是线程安全的?如何保证多线程下 i++ 结果正确? 1. 什么是线程安全和线程不安全? 什么是线程安全呢?当多个线程并发访问某个Java对象时,无论系统如何调度这些线程,也无论这些线程将如何交替操作,这个对象都能表现出一致的.正确的行为,那么对这个对象的操作是线程安全的. 如果这个对象表现出不一致的.错误的行为,那么对这个对象的操作不是

  • Java十分钟入门多线程中篇

    目录 1.线程的调度: 1.设置优先级(Priority): 2.休眠(sleep) 3.强制运行(join) 4.礼让(yield) 2.定时器线程: 3.线程的同步: 举例说明: 我们知道飞机在天上飞行是有固定的航线(可以理解成线程),每个机场都有最大的运行负载能力,当运行情况超过了负载能力的时候,这就需要塔台调度参与,会根据每架飞机的优先级排序.当在航线的时候,如果出现紧急情况,会让其他飞机避让,让这架飞机优先级提高,先降落.这就是调度,计算机程序线程运行也是这样的. 1.线程的调度: 在

  • Java十分钟入门多线程下篇

    目录 1.线程池: 2.创建线程池: 1.newCacheThreadPool: 2.newSingleThreadExecutor: 3.newFixedThreadPool(inta): 4.newScheduledTreadPool: 3.线程池创建自定义线程: 4.Runnable和Callable的区别: 5.线程池总结: 1.线程池: 什么是线程池? 咱们也不看长篇大论,通俗的来讲,线程池就是装线程的容器,当需要用的时候去池里面取出来,不用的时候放回去或者销毁.这样一个线程就可以反复

  • Java十分钟精通String类的各种使用方法

    String String类: 代表字符串,提供了开发中常用的字符串处理的方法,如:求字符串的长度.截取字符串.替换字符串等方法,符串是常量,它的值创建之后就不可以再修改了. 首先我们先查一下官方文档,看看官方给String类定了什么方法: String也是属于java.lang包,所以不需要导入,这里就部分展示,全部的内容可以参考: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.htm

  • Java十分钟精通Lambda表达式

    目录 1.简介 2.Lambda表达式的使用: 1.在普通方法内的使用 2.带参方法的使用 3.Lambda表达式实现多线程 4.Lambda表达式操作运算 5.Lambda表达式方法引用 6.Lambda表达式对集合的使用 3.总结 1.简介 首先Lambda表达式是属于Java8的 一个新特性,提供Java编程中对于函数式编程的支持,有助于代码的简洁,可以取代大半部分的匿名函数,尤其对于集合的遍历和集合的操作,极大的简化了代码. Lambda表达式的主体: 函数式接口: 注意: Lambda

  • Java十分钟精通多态与抽象类的使用与原理

    我们知道Java的三大特性:封装.继承.多态.前两个之前在Java入门(六)已经讲到,现在来讲多态这个特性. 什么是多态? 多态顾名思义即为多种形态的意思 Java中多态的含义: 发送消息给某个对象,让这个对象自行决定采用哪种行为响应这个消息 子类对象的引用赋值给父类引用变量来实现动态的方法调用 Java中形成多态的前提: 继承 父类方法的重写 向上转型 我对多态的解释: 比如我们,是人,也是学生,也是年轻人,我可以用人的身份去做事情,也可以用学生的身份去买学生票,也可以用年轻人的身份做公益,这

  • Java十分钟快速掌握单例模式

    目录 前言 1.什么是单例模式: 2.单例模式的优缺点: 3.懒汉模式(比较常用) 4.饿汉模式[推荐使用] 5.单例模式的应用场景 6.单例模式的应用实例 小结: 前言 首先在Java中有23种设计模式: 创建型模式: 工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式结构型模式: 适配器模式.装饰者模式.代理模式.外观模式.桥接模式.组合模式.享元模式行为型模式::策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释

  • Spring Security十分钟入门教程

    目录 写在前面 目标 开始 不引入Spring Security访问接口 引入Spring Security访问接口 退出登录 后记 写在前面 我们在学习技术的过程中,学习的渠道大概有以下几种:看书,视频,博客.我们会发现,一种技术开始流行的时候,各种形式的讲述也就出现了.那么,出书,录视频,写博客的人,在他们之前,是没有什么现成的东西让他们学习的,他们是怎么上手的呢?换句话说,怎么才能有效的快速的上手一门技术呢? 这篇文章,我们一起从零开始学习SpringSecurity,技术点不重要,重要的

  • Java十道入门易踩坑题分析前篇

    目录 1,java基本类型 2,java包装类 3,Java编译 4,JDK,JVM,JRE 5,类型转换 6,转义字符 7,标识符 8,类型转换 9,赋值符号 10,打印一个字符串 1,java基本类型 下面属于java基本数据类型的有( ) A.String B.byte C.char D.Array Java基本数据类型分为三种,数值型,字符型,布尔型 数值型: 整型:byte.short.int.long 浮点型:double.float 字符型:char 布尔型:boolean Arr

  • Java十道入门易踩坑题分析后篇

    目录 一,写在前面 二,代码分析 代码分析① 代码分析② 代码分析③ 代码分析④ 代码分析⑤ 代码分析⑥ 代码分析⑦ 代码分析⑧ 代码分析⑨ 代码分析⑩ 一,写在前面 本篇主要讲类和对象这一章节的踩坑题,这一章也相对复杂和难理解,面试也是常考的一类题,我分析的都是比较经典的,读者觉得自己学习的不够扎实,可以收藏,如果觉得写发不错的话,求个免费的赞,谢谢! 二,代码分析 代码分析① 阅读如下代码. 请问,对语句行 test.hello(). 描述正确的有() package NowCoder; c

随机推荐