Java多线程(二)

news2024/12/30 1:36:07

目录

一、线程的使用

Thread类的有关方法

线程的调度

调度策略:

java的调度方法

线程的优先级

线程的优先等级

如何获取优先级

线程有关方法及线程优先级练习

线程的分类

二、线程的生命周期

 三、线程的同步(一)(线程安全问题)

使用继承Thread类创建线程的方式(存在线程安全问题)

 使用实现Runnable接口创建线程的方式(存在线程安全问题)

synchronized的使用方法

1、同步代码块

使用同步代码块解决上述线程安全问题

2、同步方法

使用同步方法块解决上述线程安全问题


一、线程的使用

Thread类的有关方法

1、start():启动当前线程;调用当前线程的run()方法
2、run():通常需要重写Thread类中的run()方法,建创建的线程执行的操作声明在此方法中
3、currentThread():静态方法,返回执行当前代码的线程
4、getName():获取当前线程的名字
5、setName():设置当前线程的名字
6、yield():释放当前CPU执行权
7、join():在线程A中,调用线程B的join()方法,此时线程A就进入阻塞状态,直到线程B执行完后,线程A才结束阻塞状态
8、stop():强制结束当前线程(已过时)
9、sleep():让当前线程阻塞一段时间(单位:毫秒)
10、isAlive():判断当前线程是否存活

线程的调度

调度策略:

  • 时间片

  •  抢占式:优先级高的线程抢占CPU

java的调度方法

  • 同优先级线程组先进先出队列,使用时间片策略
  • 对高优先级,使用优先调度的抢占式策略

线程的优先级

线程的优先等级

> MAX_PRIORITY:10
> MIN_PRIORITY:1
> NORM_PRIORITY:5--->默认优先级

如何获取优先级

> getPriority():获取当前线程的优先级
> setPriority(int newPriority):设置线程的优先级

说明:优先级高的要先抢占线程的执行权,但只是从概率上讲,优先级高的线程高概率情况下被执行,但并不意味着只有当优先级高的线程执行完以后,低优先级的线程才开始执行

线程有关方法及线程优先级练习

class ThreadMethod extends Thread{
    @Override
    public void run() {
        for(int i=0;i<=25;i++){
            if(i%2==0){

                try {
                    //阻塞一秒
                    sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(getName()+":"+getPriority()+":"+i);
            }

            if(i%20==0){
                this.yield();
            }

        }
    }

    public ThreadMethod(String name){
        super(name);
    }
}


public class ThreadMethodTest {
    public static void main(String[] args) {
        ThreadMethod m1=new ThreadMethod("分线程1");
//        m1.setName("线程1");

        //设置分线程的优先级
        m1.setPriority(Thread.MAX_PRIORITY);
        m1.start();

        //给主线程命名
        Thread.currentThread().setName("主线程");
        //设置主线程优先级
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

        for(int i=0;i<=25;i++){
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
            }
            if(i==20){
                try {
                    m1.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

运行结果如下:

线程的分类

Java中的线程分为两类:一种是守护线程,一种是用户线程。

它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。

守护线程是用来服务用户线程的,通过在start()方法前调用 thread.setDaemon(true)可以把一个用户线程变成一个守护线程。

 Java垃圾回收就是一个典型的守护线程。

若JVM中都是守护线程,当前JVM将退出。

二、线程的生命周期

JDK中用Thread.State类定义了线程的几种状态

要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

  • 新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:当新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时该线程具备了运行条件,只是没分配到CPU资源
  • 运行:当处于就绪状态的线程被调度并获得CPU资源时,便进入运行状态,run()定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人认为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了自己的全部工作或线程被提前强制性的终止或出现异常导致结束

 三、线程的同步(一)(线程安全问题)

以具体例题来说明线程安全问题

模拟火车站售票程序,开启三个窗口售票,总票数为100张

使用继承Thread类创建线程的方式(存在线程安全问题)

public class WindowTest1 {
    public static void main(String[] args) {
        Window w1=new Window();
        Window w2=new Window();
        Window w3=new Window();
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        w1.start();
        w2.start();
        w3.start();

    }
}

class Window extends Thread{
    private static int ticket=100;

    @Override
    public void run() {
        while(true){
            if(ticket>0){
                System.out.println(getName()+":卖票,票号为:"+ticket);
                ticket--;
            }else{
                break;
            }

        }
    }
}

部分运行结果:

 使用实现Runnable接口创建线程的方式(存在线程安全问题)

public class WindowTest2 {
    public static void main(String[] args) {
        Window2 w=new Window2();
        Thread thread1 = new Thread(w);
        Thread thread2 = new Thread(w);
        Thread thread3 = new Thread(w);
        thread1.setName("窗口1");
        thread2.setName("窗口2");
        thread3.setName("窗口3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window2 implements Runnable{

    private int ticket=100;
    @Override
    public void run() {
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+",卖票,票号为:"+ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}

部分运行结果如下:

 1. 多线程出现了安全问题

2. 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。

3. 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。

synchronized的使用方法

java对于多线程的安全问题提供了专业的解决放方式:同步机制

1、同步代码块

synchronized(同步监视器){

        //需要被同步的代码;

}

说明:

  • 操作共享数据的代码,即为需要被同步的代码 
  • 共享数据:多个线程共同操作的变量
  • 同步监视器,俗称:锁
    • 任何对象都能充当锁
    • 多个线程必须共享同一把锁

使用同步代码块解决上述线程安全问题

使用继承Thread类的方式
public class WindowTest1 {
    public static void main(String[] args) {
        Window w1=new Window();
        Window w2=new Window();
        Window w3=new Window();
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        w1.start();
        w2.start();
        w3.start();

    }
}

class Window extends Thread{
    private static int ticket=100;
   private static Object obj1=new Object();

    @Override
    public void run() {
        while(true){
            //方式二:synchronized (obj1){
            synchronized (Window.class){
                //类也是对象 相当于 Class clazz=Window.class
                //Window.class只会加载一次
                if(ticket>0){
                    System.out.println(getName()+":卖票,票号为:"+ticket);
                    ticket--;
                }else{
                    break;
                }
            }

        }
    }
}
使用实现Runnable接口的方式
public class WindowTest2 {
    public static void main(String[] args) {
        Window2 w=new Window2();
        Thread thread1 = new Thread(w);
        Thread thread2 = new Thread(w);
        Thread thread3 = new Thread(w);
        thread1.setName("窗口1");
        thread2.setName("窗口2");
        thread3.setName("窗口3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window2 implements Runnable{
    Object obj=new Object();
    private int ticket=100;
    @Override
    public void run() {
        while(true){
           synchronized (this){ //此时的this:唯一的window2的对象  //方式二:synchronized(obj) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ",卖票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

2、同步方法

如果操作共享数据的代码完整的声明在一个方法中,不妨将这个方法声明为同步的

说明:

  • 同步方法仍然涉及到同步监视器,只是不需要显式的声明
  • 静态同步方法中,同步监视器是:this(默认)
  • 非静态方法中,同步监视器是:当前类本身

使用同步方法块解决上述线程安全问题

使用继承Thread类的方式

public class WindowTest1_2 {
    public static void main(String[] args) {
        Window1_2 w1=new Window1_2();
        Window1_2 w2=new Window1_2();
        Window1_2 w3=new Window1_2();
        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");
        w1.start();
        w2.start();
        w3.start();

    }
}

class Window1_2 extends Thread{
    private static int ticket=100;

    @Override
    public void run() {
        while(true){
            show();
        }
    }
    private static synchronized void show(){//同步监视器:t1,t2,t3(此种方法是错误的)
        //必须保证此方法是静态的
        //此时的同步监视器:Window1_2
        if(ticket>0){
            System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
            ticket--;
        }
    }
}

使用实现Runnable接口的方式

public class WindowTest2_2 {
    public static void main(String[] args) {
        Window2_2 w=new Window2_2();
        Thread thread1 = new Thread(w);
        Thread thread2 = new Thread(w);
        Thread thread3 = new Thread(w);
        thread1.setName("窗口1");
        thread2.setName("窗口2");
        thread3.setName("窗口3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class Window2_2 implements Runnable{

    private int ticket=100;
    @Override
    public void run() {
        while(true){
           show();
        }
    }
    private synchronized void show(){//同步监视器:this
        if(ticket>0){
            System.out.println(Thread.currentThread().getName()+",卖票,票号为:"+ticket);
            ticket--;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】基本指令(二)

文章目录rmdir&&rm 指令nano 指令whoami 指令man 指令cp 指令mv 指令echo 指令cat 指令wc 指令more 指令less 指令head 指令tail 指令date 指令cal 指令rmdir&&rm 指令 &#x1f495; rmdir是一个与mkdir相对应的命令。 mkdir是建立目录&#xff0c;而rmdir是…

UML之类图

概要 类图以反映类的结构(属性、操作)以及类之间的关系为主要目的&#xff0c;描述了软件系统的结构&#xff0c;是一种静态建模方法。类图中的“类”与面向对象语言中的“类”的概念是对应的&#xff0c;是对现实世界中的事物的抽象。元素解析 类 从上到下分为三部分&#…

Jetson Nx 串口接收数据丢失首字节问题

1 问题描述 I write a uart program using c on Jetson Nx(Jetpack 4.6.1,Ubuntu version 18.04 LTS) to communicate with a PC. On PC there’s a uart simulator( as below figure 1) sending data at a period of one second, 30 bytes data are : EB90021112131415161718…

VUE综合数据库编程

VUE综合数据库编程 案例要求 基于node expressvue clielementUImysql&#xff0c;在如图8.14所示的功能的基础上增加一个输入框用于输入商品的id&#xff0c;增加一个“删除”按钮&#xff0c;完成根据id删除商品的功能&#xff08;删除后的结果通过查看数据表goods的最新数据…

LinkedIn领英怎么避免封号?封号怎么解决?(建议收藏)

使用领英的朋友都知道&#xff0c;领英是很容易封号的。辛辛苦苦经营到上千好友的账号&#xff0c;第二天登录&#xff0c;提示“您的账号受到限制&#xff0c;暂时无法使用”。 例如1&#xff1a; 例如2&#xff1a; Linkedin如何避免封号&#xff1f; 大家肯定不愿看到这…

【JavaSE】Comparable接口和Comparator接口

文章目录一、Comparable接口二、Comparator接口一、Comparable接口 当我们要比较两个类的大小时&#xff0c;我们该如何比较呢&#xff0c;是这样吗&#xff1f; 这样写是错误的&#xff0c;所以我们需要用到接口Comparable的CompareTo方法。 而ComparaTo是抽象方法&#x…

74cms骑士人才招聘系统源码SE版 v3.16.0

介绍&#xff1a; 74cms骑士人才招聘系统是一项基于PHPMYSQL为核心开发的一套专业人才招聘系统。骑士人才系统拥有十多年的人才招聘系统运营解决方案&#xff0c;同时我们提供智能化招聘系统、招考系统等全方位系统化解决方案。 74cms骑士人才招聘系统SE版&#xff1a; 更懂运…

Redhat(9)-磁盘分区-parted-swap-lvm-stratis-vdo-tuned

1.parted 2.swap 3.lvm 4.stratis 5.vdo 6.tuned 1.MBR: MASTER BOOT LOADER 逻辑分区&#xff1a;可以直接格式化使用 扩展分区&#xff1a;不可以直接格式化使用 2.GPT分区 1.parted 2.swap 虚拟内存 linux vmmemoryswap Hibernate :内存 3.lvm 3.1实现的功能和优点&…

前三强重磅揭晓!华秋第八届硬创大赛-全国总决赛路演活动成功举办!

11月19日&#xff0c;华秋第八届硬创大赛-全国总决赛路演活动在深圳高交会成功举办。此次项目路演活动是在深圳市福田区科技创新局指导下&#xff0c;由深圳华秋电子有限公司主办&#xff0c;深圳高交会联合主办的硬件创新领域专业赛事。共13个硬科技领域的优秀项目从众多报名项…

零基础入门JavaWeb——Web基本概念

一、服务器和客户端的概念 1.1 客户端的作用 与用户进行交互&#xff0c;用于接收用户的输入、展示服务器端的数据以及向服务器端传递数据。 1.2 服务器的作用 与客户端进行交互&#xff0c;接收客户端的数据、处理具体的业务逻辑、传递给客户端需要的数据。 1.3 什么是服务…

王道考研——操作系统(第二章 进程管理)

一、进程的概念、组成、特征 进程的概念 进程的组成——PCB 进程的组成——程序段、数据段 知识滚雪球&#xff1a;程序是如何运行的&#xff1f; 进程的组成 进程的特征 知识回顾与重要考点 二、进程的状态与转换 进程的状态——创建态、就绪态 进程的状态——运行态 进程的…

5G+北斗:人员定位系统为化工厂定位赋能

人员定位系统是集计算机软硬件、信息采集处理、无线数据传输、网络数据通讯、自动控制等技术多学科综合应用为一体的自动识别信息技术产品&#xff0c;可以实现对不同人、物在不同状态下的智能识别。 物联网时代&#xff0c;人们以感知为目的实现人与人、人与物、物与物全面互联…

【栈和队列的相互转换】

目录&#xff1a;前言一、 用队列实现栈&#xff08;一&#xff09; 题目分析1.队列基本操作2.画图分析3.翻译图解&#xff08;二&#xff09;整体代码二、用栈实现队列&#xff08;一&#xff09; 题目分析1.栈基本操作2.画图分析3.翻译图解&#xff08;二&#xff09;整体代码…

wy的leetcode刷题记录_Day47

wy的leetcode刷题记录_Day47 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2022-11-20 前言 补 目录wy的leetcode刷题记录_Day47声明前言799. 香槟塔题目介绍思路代码收获105. 从前序与中序遍历序列构造二叉树题目介绍思路代码收获79…

优思学院|精益六西格玛的成本效益怎么样?

所有精益六西格玛的实施都以项目工作为中心&#xff0c;因此可以用投资回报率&#xff08;ROI&#xff09;确定成本效益。项目可以集中在通过改善营收或降低成本&#xff08;或两者&#xff09;来提高净利润。 它们也可以侧重于通过减少资产&#xff08;通常是库存或应收账款&…

迅为IMX8M开发板2gst-inspect-1.0测试

gstreamer 开发中&#xff0c;一般开发思路为&#xff1a;寻找命令行实现--命令行验证--将命令行集成到代码中---代码工程 化。当然如果你要代码更优雅一点&#xff0c;可以用命令行用对应的 API 来实现。本节来总结一下 gstreamer 的常用 使用过程。 gst-inspect 可以查看插件…

新鲜出炉,Linux眼花缭乱的小寄巧

14天学习训练营导师课程&#xff1a; 互联网老辛《 符合学习规律的超详细linux实战快速入门》 努力是为了不平庸~ 学习有些时候是枯燥的&#xff0c;但收获的快乐是加倍的&#xff0c;欢迎记录下你的那些努力时刻&#xff08;学习知识点/题解/项目实操/遇到的bug/等等&#xf…

MySQL_数据库的约束

文章目录 1. NULL约束 2. UNIQUE(唯一约束) 3. DEFAULT(默认值约束) 4. PRIMARY KEY(主键约束) 5. FOREIGN KEY(外键约束) 数据库的约束就是关系型数据库给我们提供的一种"校验数据"合法性的机制 1. NULL约束 创建表时,可以指定某列不为空 create table stud…

MindFusion Scheduler for JavaScript 2.0 Crack

用纯 JAVASCRIPT 编写的交互式调度库--MindFusion Scheduler for JavaScript MindFusion 为所有需要呈现交互式时间表、活动日程或约会日历的应用程序提供了完整的解决方案。完全响应、高度可定制且易于集成的 JavaScript 调度库&#xff0c;您可以根据需要快速编程。 本土化 本…

Centos7 linux 中 防火墙操作命令及SSH远程连接

文章目录查看防火墙状态开启防火墙关闭防火墙查看对外开放的端口状态对外开发端口SSH 工具远程连接VMware 虚拟机查看防火墙状态 systemctl status firewalld开启防火墙 systemctl start firewalld若遇到无法开启 先用&#xff1a;systemctl unmask firewalld.service 然后&a…