20章节多线程

20.1线程简介
世间有很多工作都是可以同时完成的。例如,人体可以同时进行呼吸、血液循环、思考问题等活用户既可以使用计算机听歌,也可以使用它打印文件。同样,计算机完全可以将多种活动同时进这种思想放在 Java 中被称为并发,而将并发完成的每一件事情称为线程。在Java 中,并发机制非常重要。在以往的程序设计中,我们都是一个任务完成后再进行下一个任,这样下一个任务的开始必须等待前一个任务的结束。Java 语言提供了并发机制,程序员可以在程r中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程

线程的特点

20.2创建线程
在Java中主要提供两种方式实现线程,分别继承java.lang.Thread类与实现java.lang.Runnable接口

20.2.1继承Thread类
Thread 类是java.lang 包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线需要建立Thread实例。Thread 类中常用的两个构造方法如下:口 public Thread0:创建一个新的线程对象。
口 public Thread(String threadName): 创建一个名称为 threadName 的线程对象继承Thread类创建一个新的线程的语法如下:
public class ThreadTest extends Thread!
完成线程真正功能的代码放在类的run()方法中,当一个类继承 Thread类后,就可以在该类中影run()方法,将实现该线程功能的代码写入run()方法中,然后调用 Thread类中的start()方法执行线
也就是调用run()方法。

Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写#run0方法中。run0方法必须使用以下语法格式:
public void run()

注意

20.2.2实现Runnable接口
说明

        可以查询API,从中可以发现,实质上Thread类实现了Runnable接口,其中的run()方法正是对Runnable接口中的run()方法的具体实现。

实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象与Thraed对象相关联,Thread类中有以下两个构造方法:

public Thread(Runnable target).

public Thread(Runnable target,Strug name)

这两个构造方法的参数中都存在Runnable实例,使用以上构造方法就可以江Runnable实例与T和Thread实例相关联。
20.3线程的生命周期

20.4操作线程的方法
20.4.1线程的休眠
一种能控制线程行为的方法是调用 sleep方法,seep0方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。在前面的实例中,已经演示过 sleep0方法,它通常是在 run0方法内的循环中被使用。sleep0方法的语法如下:

try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}

上述代码会使线程在 2 秒之内不会进入就绪状态。由于 sleep0方法的执行有可能抛出terruptedException 异常,所以将 sleep0方法的调用放在 try-catch 块中。虽然使用了 sleep0方法的线程一段时间内会醒来,但是并不能保证它醒来后进入运行状态,只能保证它进入就绪状态。 
package ershi;
 
import java.awt.*;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.*;
 
public class SleepMethodTest extends JFrame{
    private static Color[] color= {Color.BLACK,Color.BLUE,Color.CYAN,Color.GREEN,Color.ORANGE,Color.YELLOW,Color.RED,Color.PINK,Color.LIGHT_GRAY};
    private static final Random rand=new Random();
    
    private static Color getC() {
        return color[rand.nextInt(color.length)];
    }
    public SleepMethodTest() {
        Thread t=new Thread(new Runnable() {
            int x=30;
            int y=50;
            
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(100);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    Graphics graphics =getGraphics();
                    graphics.setColor(getC());
                    graphics.drawLine(x, y, 100, y++);
                    if(y>=80) {
                        y=50;
                    }    }    }    });
        t.start();
    }
    public static void main(String[] args) {
        init(new SleepMethodTest(),100,100);
    }
    public static void init(JFrame frame,int width, int height) {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, height);
        frame.setVisible(true);
    }
}

20.4.2线程的加入
如果当前某程序为多线程程序,假如存在一个线程 A,现在需要插入线程 B,并要求线程B免行完毕,然后再继续执行线程 A,此时可以使用 Thread 类中的join0方法来完成。这就好比此时读者在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。当某个线程使用 join(方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再缘续行。下面来看一个使用join0方法的实例。
package ershi;
 
import java.awt.BorderLayout;
 
import javax.swing.JFrame;
import javax.swing.JProgressBar;
 
public class JoinTest extends JFrame{
    private Thread threadA;
    private Thread threadB;
    private JProgressBar progressBar=new JProgressBar();
    private JProgressBar progressBar2=new JProgressBar();
    
    public static void main(String[] args) {
        JoinTest test = new JoinTest();
        test.setVisible(true);
    }
    public JoinTest() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(200,200,200,100);
        getContentPane().add(progressBar,BorderLayout.NORTH);
        getContentPane().add(progressBar2,BorderLayout.SOUTH);
        progressBar.setStringPainted(true);
        progressBar2.setStringPainted(true);
        threadA=new Thread(new Runnable() {
            int count =0;
            public void run() {
                while(true) {
                    progressBar.setValue(++count);
                    try {
                        Thread.sleep(100);
                        threadB.join();
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }}}    });
        threadA.start();
        
        threadB=new Thread(new Runnable() {
            int count =0;
            public void run() {
                while(true) {
                    progressBar2.setValue(++count);
                    try {
                        Thread.sleep(100);
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(count==100)
                    break;
                    }}});
        threadB.start();
    }
}

结果

20.4.3线程的中断
以往有的时候会使用 stop0方法停止线程,但当前版本的JDK 早已废除了 stop0方法,不建议愤stop0方法来停止一个线程的运行。现在提倡在 run0方法中使用无限循环的形式,然后使用一个布尔
标记控制循环的停止。如果线程是因为使用了 sleep0或 wait0方法进入了就绪状态,可以使用 Thread类中intemupt0方注使线程离开 run0方法,同时结束线程,但程序会抛出InterruptedException 异常,用户可以在处理滨常时完成线程的中断业务处理,如终止 while 循环。
下面的实例演示了某个线程使用 interrupted0方法,同时程序抛出了 InterruptedException异常,在异常处理时结束了 while 循环。在项目中,经常在这里执行关闭数据库连接和关闭 Socket 连接等作
package ershi;
 
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
 
public class InterruptedSwing extends JFrame{
    
    public InterruptedSwing(){
        JProgressBar progressBar=new JProgressBar();
        getContentPane().add(progressBar,BorderLayout.NORTH);
        JButton button =new JButton("停止");
        Component progressBar2;
        getContentPane().add(button,BorderLayout.SOUTH);
        progressBar.setStringPainted(true);
        Thread t=new Thread(new Runnable() {
            int count =0;
            public void run() {
                while(true) {
                    progressBar.setValue(++count);
                    try {
                        Thread.sleep(100);
                    }catch(InterruptedException e) {
                        System.out.println("当前线程被中断");
                        break;
                    }
                }
            }
        });
                    button.addActionListener((ActionListener) new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            t.interrupt();
                        }
                    });
                    t.start();
        }
    public static void init(JFrame frame,int width, int height) {
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width,height);
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        init(new InterruptedSwing(),100,100);
    }
}

结果

20.4.4线程的礼让
Thread类中提供了一种礼让方法使用——yiled()方法表示

它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程

但这仅是一个暗示,没有任何以一种机制保证当前线程会将资源礼让

20.5线程的优先级
每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的概率比较小,如垃圾回收线程的优先级就较低

Thread 类中包含的成员变量代表了线程的某些优先级,如 ThreadMIN PRIORITY(常数 1)ThreadMAX PRIORITY(常数 10)ThreadNORM PRIORITY(常数 5)。其中,每个线程的优先级都在ThreadMIN PRIORITY~ThreadMAX PRIORITY,在默认情况下其优先级都是 ThreadNORMPRIORITY。每个新产生的线程都继承了父线程的优先级。
在多任务操作系统中,每个线程都会得到一小段 CPU 时间片运行,在时间结束时,将轮换另一个线程进入运行状态,这时系统会选择与当前线程优先级相同的线程予以运行。系统始终选择就绪状态下优线程B线程A先级较高的线程进入运行状态。
package ershi;
 
public class PriorityTest implements Runnable {
    String name;
    
    public PriorityTest(String name) {
        this.name=name;
    }
    @Override
    public void run() {
        String tmp="";
        for(int i= 0;i<50000;i++) {
            tmp +=i;
        }
        System.out.println(name+"线程完成任务");
    }
    public static void main(String[] args) {
        Thread a=new Thread(new PriorityTest("A"));
        a.setPriority(1);
        Thread b=new Thread(new PriorityTest("B"));
        a.setPriority(3);
        Thread c=new Thread(new PriorityTest("C"));
        a.setPriority(7);
        Thread d=new Thread(new PriorityTest("D"));
        a.setPriority(10);
        a.start();
        b.start();
        c.start();
        d.start();
    }
}

20.6线程同步
单线程只能做一件事,后面的事情需要前面的事情完成后才可以进行,但如果使用多线程,就会发生两个线程抢占资源的问题,

防止这些资源访问的冲突、Java提供了线程同步的机制来防止访问的冲突

20.6.1线程安全
实际开发中、使用多线程程序的情况很多,如银行排号系统、火车站售票系统等。这种多线程的程李通常会爱生问题,以大车站售票系统为例,在代码中判断当前票数是否大于 0,如果大于0则执行蕊该票出售绘乘客的功能,但当两个线程同时访问这段代码时(假如这时只剩下一张票),第一个线稳蒋票售出,与此同时第二个线程也已经执行完成判断是否有票的操作,并得出票数大于0的结论,是它也获行售出操作,这样就会产生负数。所以,在编写多线程程序时,应该考虑到线程安全问题实质上线程安全问题来源于两个线程同时存取单一对象的数据。
锅如,在项目中创建 ThreadSafeTest 类,该类实现了 Runnable 接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能的代码如下:
示例:

package ershi;
 
public class ThreadSafeTest implements Runnable{
    int num=10;
      
    public void run() {
            while(true) {
                
                if(num>0) {
                try {
                    Thread.sleep(500);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"————票数"+num--);
                }
            }
        }
    public static void main(String[] args) {
        ThreadSafeTest t =new ThreadSafeTest();
        Thread tA = new Thread(t,"线程一");
        Thread tB = new Thread(t,"线程二");
        Thread tC = new Thread(t,"线程三");
        Thread tD = new Thread(t,"线程四");
        tA.start();
        tB.start();
        tC.start();
        tD.start();
    }
}

20.6.2线程同步机制

1.同步块

Java中提供了同步机制,可以有效的防止资源冲突,同步机制使用synchronized关键字,使用该关键字包含的代码块称为同步块,也称临界区语法如下:

通常将共享资源 synchronized定义的区域内,这样当其他线程获取这个锁时,就必须等待被释放后才可以进入该区域

2同步方法
同步方法就是在方法面前使用synchronized关键字修饰的方法,语法如下:

synchronized void f(){}

当某个对象调用同步方法时该对象的其他方法必须等待该同步方法执行完毕后才能被执行

例题7

package ershi;
 
public class ThreadSafeTest implements Runnable{
    int num=10;
      
    public void run() {
            while(true) {
                synchronized(this) {
                if(num>0) {
                try {
                    Thread.sleep(500);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"————票数"+num--);
                }
            }
        }
    }
    public static void main(String[] args) {
        ThreadSafeTest t =new ThreadSafeTest();
        Thread tA = new Thread(t,"线程一");
        Thread tB = new Thread(t,"线程二");
        Thread tC = new Thread(t,"线程三");
        Thread tD = new Thread(t,"线程四");
        tA.start();
        tB.start();
        tC.start();
        tD.start();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端八股文

前端八股文 目录 前端八股文1.css选择优先级&#xff1f;2.px与rem区别&#xff1f;3.重绘与重排的区别&#xff1f;4.元素水平垂直居中的方法&#xff1f;5.什么是闭包&#xff0c;闭包有什么特点&#xff1f;6.什么是事件委托&#xff1f;7.什么是原型链&#xff1f;8.new操作…

【Jenkins】Centos环境安装Jenkins(通过rpm安装)

在Centos操作系统中通过rpm安装Jenkins 参考官网 https://www.jenkins.io/doc/book/installing/linux/#red-hat-centos 1、下载安装Jdk17 下载安装 # 更新您的系统&#xff0c;不一定需要 # sudo yum -y update # 安装将用于下载 Java 17 二进制文件的 wget 命令行工具。 s…

C++STL的stack和queue(超详解)

文章目录 前言stack栈的题目最小栈JZ31 栈的压入、弹出序列 stack的模拟实现queue的模拟实现 前言 栈和队列这一块其实有数据结构的基础&#xff0c;学起来非常简单。 stack 栈的成员函数就这么写&#xff0c;除了emplace其他都已经非常熟悉了。 stack没有迭代器吗&#xff…

10个前端开发不容错过的工具网站

作为开发人员&#xff0c;我们经常寻找合适的工具和资源来帮助日常开发工作。但是很多好用的工具网站尤其是国外的网站很多人都错过了。 这里我整理了一份包含 10 个网站的列表&#xff0c;这些网站或许可以帮助到作为前端开发者的你。 1、MDN Web 文档 MDN文档无疑是 Web 开…

【Linux】锁的简单封装以及原理解析

文章目录 一、锁的原理过程1&#xff1a;过程2过程3过程4 二、 锁的简单封装1.LockGuard.hpp2.使用1.正常锁的使用2.使用封装后的 总结 一、锁的原理 为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条…

让艺术触手可及!实时云渲染赋能真浪数字艺术馆首展

2023年5月18日&#xff0c;由真浪数字艺术和EZVR联合打造的真浪数字艺术馆首展–「破界交织」让艺术更自由&#xff0c;正式与大家相见。此次展览分为五个主题展馆&#xff0c;汇聚了来自全球各领域的19位青年数字艺术家一同探讨虚实共生、人机共生和万物共生的艺术创作。 真浪…

低代码开发与传统软件开发:未来趋势与竞争格局

近年来&#xff0c;低代码开发平台的快速发展引起了各行各业的广泛关注。低代码开发平台简化了软件开发的复杂性&#xff0c;提供了更快速、更灵活的开发方式。于是&#xff0c;许多人开始产生一个疑问&#xff1a;未来低代码开发是否会取代传统软件开发&#xff1f;今天这篇文…

【网络编程之初出茅庐】

前言&#xff1a;本章主要先讲解一些基本的网络知识&#xff0c;先把基本的知识用起来&#xff0c;后续会更深入的讲解底层原理。 网络编程的概念 网络编程&#xff0c;指网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff08;或称为网络数…

处理获取当前日期---------------年月日//时分秒

当前时间&#xff0c;先分组匹配&#xff0c;以数组下标索引匹配定义的汉字进行替换 处理日期方法 /* 日期格式化 */ const formatTime function formatTime(time, template) {if (typeof time ! "string") {time new Date().toLocaleString(zh-CN, { hour12: fal…

【学习笔记】Linux(基础知识)

第1章 Linux概况 1.1 Linux起源 四个重要的支柱: ①Unix操作系统; ②Minix操作系统; ③GNU计划; ④Internet网络。 1. Unix操作系统 UNIX的诞生 1971年,用汇编语言首先开发成功16位UNIX系统 1973年,用C语言重写了UNIX系统 创始人:Ken Thompson & Dennis Ritch…

phpstudy搭建WordPress教程

一、phpstudy新建配置WordPress 打开phpstudy&#xff0c;启动Apache&#xff08;或者Nginx&#xff09;和MySQL服务 来到数据库部分&#xff0c;点击[创建数据库]&#xff0c;填写新建数据库的名称&#xff0c;用户名以及密码&#xff0c;完成后点击确认 来到网站部分&#x…

mysql更新某个字段=这个字段+字符串

当我们像c#中用拼接执行sql语句时&#xff0c;如下&#xff1a; UPDATE abpusers set UserNameqyUserName where UserNameqy-wh 会出现以下错误&#xff1a; 在mysql中通过concat函数来实现 UPDATE abpusers set UserNameCONCAT(qy_,UserName) where UserNameqy-wh

逆向思考 C. Fence Painting

Problem - 1481C - Codeforces 思路&#xff1a;逆序考虑&#xff0c;因为每一块木板都是被最后一次粉刷所决定的。 从后往前开始&#xff0c;对于 c i c_i ci​来说&#xff0c; 如果这个颜色还有没有涂的木板&#xff0c;那么涂到其中一个木板即可如果这个颜色下没有未涂的…

“公益向善”|邦邦机器人积极传递企业责任感

2023年12月4日&#xff0c;由中山市场监督管理所党支部主办的“公益向善 支援接力 宪法在心中”主题活动在中山幸福里举办&#xff0c;邦邦机器人作为捐赠单位&#xff0c;用创新技术及产品赋能大众及公益&#xff0c;积极传递企业责任感&#xff0c;点亮向善之路。 邦邦机器人…

汽车电子 -- 时间同步

时间同步有两种形式&#xff0c;一种是NTP的网络校准时间&#xff0c;一种是可以CAN通信的时间同步。 一、NTP时间同步 参看&#xff1a;什么是NTP&#xff1f; 参看&#xff1a;NTP协议详解及C语言实现 网络时间协议NTP&#xff08;Network Time Protocol&#xff09;是TC…

搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 搭建消息时光机&#xff1a;深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用 引言前言第一&#xff1a;开启插件支持第二&#xff1a;springboot整合第三&am…

js 转换为数组并返回(Array.of())

Array提供了方法直接将一组值转换为数组并返回 Array.of()方法 Array.of(1,2,3) 结果

哈工大《软件工程专业导论》复习指南

哈工大软件工程专业导论复习指南 文章目录 哈工大软件工程专业导论复习指南前言引言——软件工程专业导论课程引言第一章 软件工程专业初步认知第二章 软件体系结构与生命周期第三章 软件需求工程第四章 软件设计与实现第五章 软件质量与软件工程管理第六章 软件工程教育与职业…

Python码上行动系列丛书(由北京大学出版社出版)

前言 Python码上行动系列丛书火热来袭&#x1f4a5;&#x1f4a5;&#x1f4a5; 三册在手&#xff0c;Python全掌握&#xff01;无论是初学者还是进阶玩家&#xff0c;我们都有你想要的&#xff01; 让ChatGPT带你轻松入门Python编程&#xff0c;享受编程带来的乐趣&#xff0…

MATLAB——二维小波的单层分解

%% 学习目标&#xff1a;二维小波的单层分解 %% 二维小波适合图像处理和分析&#xff0c;将图像分解为4个图像 两个维度 低通&#xff0c;高通 clear all; close all; load woman.mat; %% which woman.mat Yind2gray(X,map); %将索引图像转换为灰度图像 [c…