第二十章总结。。。

news2025/1/21 22:07:46

20.1线程简介.


20.2创建线程
2.1继承Thread类
Thread 类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread 实例。Thread类中常用的两个构造方法如下:


public Thread():创建一个新的线程对象。
public Thread(String threadName):创建一个名称为threadName的线程对象。

    继承Thread 类创建一个新的线程的语法如下:

public class ThreadTest extends Thread{
}

完成线程真正功能的代码放在类的run(方法中,当一个类继承Thread类后,就可以在该类中覆盖 run()方法,将实现该线程功能的代码写入run()方法中,然后调用Thread类中的start()方法执行线程,也就是调用run()方法。
Thread 对象需要一个任务来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在 run()方法中。run()方法必须使用以下语法格式:


public void run(){
}

注意如果 start()方法调用一个已经启动的线程,系统将抛出IllegalThreadStateException异常。

2.2实现Runnable接口(单继承,所以要使用接口)
实现接口语法:

public class Thread extends  Object implements Runnable

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


☑public Thread(Runnable target)
☑public Thread(Runnable target,String name)

这两个构造方法的参数中都存在Runnable实例,使用以上构造方法就可以将Runnable 实例与 Thread 实例相关联。
使用Runnable接口启动新的线程的步骤如下:

(1)建立Runnable 对象。
(2)使用参数为Runnable对象的构造方法创建Thread实例。(3)调用start()方法启动线程。
通过 Runnable接口创建线程时,程序员首先需要编写一个实现 Runnable接口的类,然后实例化该类的对象,这样就建立了Runnable对象;接下来使用相应的构造方法创建 Thread 实例;最后使用该实例调用Thread类中的 start()方法启动线程。

 import java.awt.Container;
 
import javax.swing.JFrame;
import javax.swing.JLabel;
 
public class SwingAndThread extends JFrame{
    int count =0;
    public SwingAndThread(){
        setBounds(300,200,250,100);    //绝对定位窗体大小与位置    
        Container container = getContentPane();    //主容器    
        container.setLayout(null);    //使窗体不使用任何布局管理器    
        lcon icon = new lmagelcon("/D20/src/1.gif");    //图标对象    
        JLabel jl = new JLabel(icon);    //显示图标的标签    
        jl.setBounds(10,10,200,50);    //设置标签的位置与大小    
        Thread t = new Thread(){    //定义匿名线程对象    
        public void run() {
        while (true) {
        jl.setBounds(count,10,200,50);    //将标签的横坐标用变量表示    
        try{
            Thread.sleep(500);    //使线程休眠 500毫秒    
        } catch (InterruptedException e){
        e.printStackTrace();}
        count += 4;    //使横坐标每次增加4    
        if (count >= 200){
        count = 10;    //当图标到达标签的最右边时,使其回到标签最左边    
        }
        }
        }
        };    t.start();    container.add(jl);    //启动线程    //将标签添加到容器中    
        setVisible(true);    //使窗体可见    
        setDefaultCloseOperation(EXIT_ON_CLOSE);    //设置窗体的关闭方式
    }
 
    public static void main(String[] args) {
        new SwingAndThread();
 
    }
 
}

20.3线程的生命周期
线程具有生命周期,其中包含7种状态,分别为出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。出生状态就是线程被创建时处于的状态,在用户使用该线程实例调用 start()方法之前线程都处于出生状态;当用户调用start()方法后,线程处于就绪状态(又被称为可执行状态);当线程得到系统资源后就进入运行状态。
一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待、休眠、阻塞或死亡状态。当处于运行状态下的线程调用Thread类中的wait()方法时,该线程便进入等待状态,进入等待状态的线程必须调用Thread类中的notify0方法才能被唤醒,而调用notifyAl1O)方法可将所有处于等待状态下的线程唤醒;当线程调用Thread类中的sleep(方法时,则会进入休眠状态。如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时线程进入就绪状态,对于阻塞的线程来说,即使系统资源空闲,线程依然不能回到运行状态。当线程的run()方法执行完毕时,线程进入死亡状态。
说明
使线程处于不同状态下的方法会在20.4节中进行讲解,在此读者只需了解线程的多个状态即可。

20.4操作线程的方法
4.1线程的休眠
    import java.awt.*;
    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;    Il定义初始坐标    
        int y=50;
        public void run(){
        while (true) {    //无限循环    
        try{    Thread.sleep(100);    //线程休眠 0.1秒    
        } 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);
        
    }
 
}

4.2线程的加入
使用join()方法加入线程

import java.awt.BorderLayout;
import javax.swing.*;
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() {    //使用匿名内部类形式初始化 Thread实例    
    int count = 0;
    public void run() {    //重写 run()方法    
            while (true) {
                progressBar.setValue(++count);    //设置进度条的当前值    
                try {
                    Thread.sleep(100);    //使线程A 休眠 100毫秒    
                    threadB.join();    //使线程B调用 join()方法    
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
    }
            });
    threadA.start();    //启动线程A
    threadB= new Thread(new Runnable(){
        int count = 0;
        public void run() {
        while (true) {
        progressBar2.setValue(++count);    //设置进度条的当前值    
        try{    Thread.sleep(100);    //使线程B休眠 100 毫秒    
        } catch (InterruptedException e) {
        e.printStackTrace();
        if (count ==100)    break;    //跳出循环    
        }
        }
        });    //启动线程B    
        threadB.start();
        }
    }

 4.3线程的中断
现在提倡在r un()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。
如果线程是因为使用了sleep()或 wait()方法:进入了就绪状态,可以使用Thread 类中interrupt)方法使线程离开run()方法,同时结束线程,但程序会会抛出 InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while 循环。
下面的实例演示了某个线程使用interrupted0方法,同时程序抛出了InterruptedException异常,在异常处理时结束了while循环。在项目中,经常在这里执行关闭数据库连接和关闭Socket连接等操作。

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
    public class InterruptedSwing extends JFrame {
        
        public InterruptedSwing(){
        JProgressBar progressBar = new JProgressBar();    //创建进度条    
        getContentPane().add(progressBar, BorderLayout.NORTH);//将进度条放置在窗体合适位置
        JButton button=new JButton("停止");
        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);    //使线程休眠 100毫秒    
        } catch (InterruptedException e){//捕捉InterruptedException 异常
            System.out.println("当前线程序被中断"); 
            break;}
        }
        }
        }
        );
        button.addActionListener(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);
        
    }
 
}

 4.4线程的礼让
Thread类中提供了一种礼让方法,使用 yield()方法表示,它只是给当前正处于运行状态的线程一
个提醒,告知它可以将资源礼让给其他线程    但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。
yield()方法使具有同样优先级的线程有过进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配 CPU 时间片来执行。

20.5线程的优先级
 

public class PT implements Runnable {
    String name;
    public PT(String name) {
    this.name = name; 
    }
    @Override
    public void run() {
    String tmp= "";
    for (int i= 0; i< 50000; i++) {
    tmp +=i;
//完成5万次字符串拼接
    }
    System.out.println(name +"线程完成任务");
    }
    public static void main(String[]args){
    Thread a = new Thread(new PT("A"));
    a.setPriority(1);    //A线程优先级最小    
    Thread b = new Thread(new PT("B"));
    b.setPriority(3);
    Thread c = new Thread(new PT("C"));    
    c.setPriority(7);    
    Thread d = new Thread(new PT("D"));
    d.setPriority(10);    //D线程优先级最大    
    a.start();    
    b.start();    
    c.start();    
    d.start();    
    }
    }
 


线程的优先级可以使用setPriority()方法调整,如   果使用该方法设置的优先级不在1~10,将产生  IllegalArgumentException 异常。   

20.6线程同步
在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同时说话、两个人同时过同一个独木桥等。所以,在多线程编程中需要防止这些资源访问的冲突。Java提供了线程同步的机制来防止资源访问的冲突。


6.1 线程安全

实际开发中,使用多线程程序的情况很多,在编写多线程程序时,应该考虑到线程安全问题,实质上线程安全问题来源于两个线程同时存取单一对象的数据。

 
    public class ThreadSafeTest implements Runnable {
        //设置当前总票数
        int num = 10;
        public void run() {
        //设置无限循环
        while (true) {
        if (num > 0){    //判断当前票数是否大于0    
        try {
        Thread.sleep(100);    //使当前线程休眠100毫秒    
        } catch (InterruptedException e) {
            e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+ "----票数"+ num--);//票数减1
        }
    }
    }
        public static void main(String[]args){
        ThreadSafeTest t= new ThreadSafeTest();    //实例化类对象    
        Thread tA = new Thread(t,"线程一");    //以该类对象分别实例化4个线程    
        Thread tB = new Thread(t,"线程二"); Thread tC = new Thread(t,"线程三"); Thread tD= new Thread(t,"线程四");
        tA.start();    //分别启动线程    
        tB.start(); 
        tC.start();
        tD.start();
        }
}

从这个结果可以看出,最后打印出的剩下的票数为负值,这样就出现了问题。这是由于同时创建了4个线程,这4个线程执行run()方法,在num变量为1时,线程一、线程二、线程三、线程四都对num 变量有存储功能,当线程一执行run()方法时,还没有来得及做递减操作,就指定它调用sleep()方法进入就绪状态,统等。这种多线程的    这时线程二、线程三和线程四也都进入了run()方法,发现num 变 如果大于0则执行    量依然大于 0,但此时线程一休眠时间已到,将num变量值递减张票),第一个线程    同时线程二、线程三、线程四也都对num变量进行递减操作,从 而产生了负值。

6.2线程同步机制
1.同步块
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用synchronized关键字, 
 语法如下: 

   
synchronized (Object){
}

通常将共享资源的操作放置在synchronized定义的区域内,这样当其他线程获取到这个锁时,就必须等待锁被释放后才可以进入该区域。Object为任意一个对象,每个对象都存在一个标志位,并具有两个值,分别为0和1。一个线程运行到同步块时首先检查该对象的标志位,如果为0状态,表明此同步块内存在其他线程,这时当期线程处于就绪状态,直到处于同步块中的线程执行完同步块中的代码后,这时该对象的标识位设置为1,当期线程才能开始执行同步块中的代码,并将Object对象的标识位设置为0,以防止其他线程执行同步块中的代码。

public class SynchronizedTest implements Runnable { 
    int num = 10;
 
//设置当前总票数
    public void run() {
        while (true){    //设置无限循环    
            synchronized (this){    //设置同步代码块    
                if (num > 0) {    //判断当前票数是否大于0    
                    try {
                        Thread.sleep(100);    //使当前线程体眠 100
                    } catch (InterruptedException e) {
                        e.printStackTrace();}
                        //票数减 1
                        System.out.println(Thread.currentThread().getName()+"--票数" + num--);
                        }
                }
            }
        }
                        public static void main(String[] args){
                        //实例化类对象
                        SynchronizedTest t = new SynchronizedTest();//以该类对象分别实例化4个线程 
                        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();
                        }
                        }

2.同步方法

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

synchronized void f(){}


当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。
修改例20.7的代码,将共享资源操作放置在一个同步方法中,代码如下:

int num = 10;
public synchronized void doit() {    //定义同步方法
if(num>0){
try{
Thread.sleep(10);
}catch(interruptedException e){
e.printStackTrace():
System.out.printin(Thread.currentThread().getName()+"-票数” +num--);
public void run(){
    while(true){
doit():    //在run()方法中调用该同步方法
 

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

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

相关文章

Sui主网升级至V1.14.2版本

Sui主网现已升级至V1.14.2版本&#xff0c;同时Sui协议升级至31版本。其他升级要点如下所示&#xff1a; #14875: [修复] 为所有权限设置共识度量值。 #14811: [Narwhal] 改进每个权限的共识信息度量的可用性。 完整变更日志&#xff1a;Release mainnet-v1.14.2 MystenL…

离散化笔记

文章目录 离散化的适用条件离散化的意思AcWing 802. 区间和CODECODE2 离散化的适用条件 离散化用于区间求和问题对于数域极大&#xff0c;而数的量很少的情况下 离散化的意思 背景&#xff1a;对于一个极大数域上的零星几个数进行操作后&#xff0c;求某段区间内的和 其实意思…

单片非晶磁性测量系统非晶特性

1. 非晶特性&#xff08;与硅钢相比&#xff09; 非晶带材的厚度很薄&#xff0c;一般为0.025 mm&#xff0c;只有取向硅钢带材的1/10左右。比总损耗很低&#xff0c;P1.5 / 50的典型值约为0.2 W/kg&#xff0c;该值是取向硅钢P1.7 / 50典型值的1/5左右。具有高磁致伸缩和低的…

(二)基于高尔夫优化算法GOA求解无人机三维路径规划研究(MATLAB)

一、无人机模型简介&#xff1a; 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 参考文献&#xff1a; [1]胡观凯,钟建华,李永正,黎万洪.基于IPSO-GA算法的无人机三维路径规划[J].现代电子技术,2023,46(07):115-120 二、高尔夫优化算法GOA简介 高尔夫优化算法…

第二十章 多线程总结

继承Thread 类 Thread 类时 java.lang 包中的一个类&#xff0c;从类中实例化的对象代表线程&#xff0c;程序员启动一个新线程需要建立 Thread 实例。 Thread 对象需要一个任务来执行&#xff0c;任务是指线程在启动时执行的工作&#xff0c;start() 方法启动线程&…

PTA_2023年软件设计综合实践_10(回溯法与分治限界法)

7-1 桥本分数 将1-9九个数不重复地赋给不同的9个元素 &#xff0c;实现形如a/bcd/eff/hi 的形式。例&#xff1a;1/265/784/39 1/325/967/84 &#xff08;注意&#xff1a;1/265/784/39 和5/781/264/39 只能算一种解&#xff09;&#xff0c;共有多少种不同的解。 语言选C #…

YOLOv5算法进阶改进(6)— 更换主干网络之ResNet18

前言:Hello大家好,我是小哥谈。ResNet18是ResNet系列中最简单的一个模型,由18个卷积层和全连接层组成,其中包含了多个残差块。该模型在ImageNet数据集上取得了很好的表现,成为了深度学习领域的经典模型之一。ResNet18的优点是可以解决深度神经网络中梯度消失的问题,使得性…

初识向量数据库

背景 现在的数据分为20%的传统结构化数据&#xff0c;80%的非结构化数据 结构化数据&#xff1a;主要单元是数值与符号&#xff0c;数据类型高度抽象且易于组织。基于数值运算与关系代数&#xff0c;可以轻松地对结构化数据进行分析。 非结构化数据&#xff1a;常见的类型包括…

荒野大镖客提示找不到emp.dll文件的5个修复方法-快速修复dll教程

今天我要和大家分享的是关于荒野大镖客缺失emp.dll的5个修复方法。我们都知道&#xff0c;荒野大镖客是一款非常受欢迎的游戏&#xff0c;但是有些玩家在玩游戏的过程中会遇到一些问题&#xff0c;比如emp.dll文件丢失。那么&#xff0c;emp.dll文件到底有什么作用呢&#xff1…

苹果Vision Pro即将量产

据界面新闻消息&#xff0c;苹果公司将在今年12月正式量产第一代MR&#xff08;混合现实&#xff09;产品Vision Pro。苹果公司对Vision Pro寄予了厚望&#xff0c;预计首批备货40万台左右&#xff0c;2024年的销量目标是100万台&#xff0c;第三年达到1000万台。 苹果的供应…

OCR文字识别工具 Cisdem OCRWizard激活最新 for Mac

为了提高内容识别的准确性&#xff0c;Cisdem OCRWizard提供供您选择两种模式&#xff1a;文件或名片。此外&#xff0c;它会自动分析的内容&#xff0c;标志着不同颜色的页面上几个区域根据给定部分的性质&#xff1a;文本&#xff08;绿色标记&#xff09;&#xff0c;图像&a…

洛谷100题DAY8

36.P1416 攻击火星 此题找出规律即可 #include<bits/stdc.h> using namespace std; int n; int main() {cin >> n;cout << max(0, n - 2);return 0; } 37.P1551 亲戚 并查集模板题目 两个人如果使亲戚就合并建立联系&#xff0c;最后进行查找即可 #incl…

String你知道多少细节(含面试题)

1 字符串初始化 常见的初始化方式有以下3种 public static void main(String[] args) {String s1 "abc";System.out.println(s1);String s2 new String("abc");System.out.println(s2);char[] s3 {a,b,c};System.out.println(s3);} 【注意】 1.Strin…

Airtest进阶使用篇!提高脚本稳定性 + 批量运行脚本!

一、背景 今天彭于晏为大家分享Airtest进阶使用篇&#xff0c;主要包含两块的内容&#xff1a; 提高脚本稳定性批量运行脚本生成测试报告 二、提高脚本稳定性 1、添加全局配置: #全局设置 ST.FIND_TIMEOUT10 #设置隐式等待时长,默认识别图片时间是30秒&#xff0c;可改为…

Redis对象系统

前言 在Redis中有许多数据结构&#xff0c;比如&#xff1a;简单动态字符串(SDS)&#xff0c;双端链表&#xff0c;字典&#xff0c;压缩列表&#xff0c;整数集合等。 Redis并没有直接使用这些数据结构来实现键值对数据库&#xff0c;而是基于这些数据结构创建了一个对象系统。…

LLM面面观之Prefix LM vs Causal LM

1. 背景 关于Prefix LM和Causal LM的区别&#xff0c;本qiang在网上逛了一翻&#xff0c;发现多数客官只给出了结论&#xff0c;但对于懵懵的本qiang&#xff0c;结果仍是懵懵... 因此&#xff0c;消遣了多半天&#xff0c;从原理及出处&#xff0c;交出了Prefix LM和Causal …

SparkRDD及算子-python版

RDD相关知识 RDD介绍 RDD 是Spark的核心抽象&#xff0c;即 弹性分布式数据集&#xff08;residenta distributed dataset&#xff09;。代表一个不可变&#xff0c;可分区&#xff0c;里面元素可并行计算的集合。其具有数据流模型的特点&#xff1a;自动容错&#xff0c;位置…

【SparkSQL】基础入门(重点:SparkSQL和Hive的异同、SparkSQL数据抽象)

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍Spark SQL的定义、特点、发展历史、与hive的区别、数据抽象、SparkSession对象。 后续会继续分享其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一…

Python三百行代码实现一简约个人博客网站(全网最小巧)

这是全互联网最小巧的博客&#xff0c;没有比这更小的了。虽然小巧&#xff0c;但功能一点儿也不弱&#xff0c;支持文章的分页展示&#xff0c;文章表格&#xff0c;图片和代码语法高亮。文章无限制分类&#xff0c;访问量统计&#xff0c;按时间和按点击量排序&#xff0c;展…

端口隔离度

端口隔离度 隔离度为&#xff08;本振或射频信号&#xff09;泄漏到其他端口的功率与输入功率之比&#xff0c;单位是dB。 比如 RF to LO Isolation 表示 射频输入信号的功率 与 泄漏到LO端口的功率 之比。 而 LO to RF Isolation 则表示 本振输入信号的功率 与 泄漏到RF端口的…