当前位置: 首页 > news >正文

java多线程-多线程技能

继承Thread类

一个类继承Thread类后创建新线程

package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 22:30
 */
public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread");
    }
}
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 15:12
 */
public class Run3 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("运行结束!");
    }
}

运行结果可以看出,新线程创建比运行结束!文字输出要慢

运行结束!
MyThread

如果让主线程休眠200ms,那样顺序将会反过来

package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 15:12
 */
public class Run3 {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        // 主线程休眠三秒
        Thread.sleep(200);
        System.out.println("运行结束!");
    }
}

运行结果

MyThread
运行结束!

使用常见的命令分析现成的信息

  1. 使用jps+jstack,在java的bin目录下打开cmd,运行以下代码后输入jps即可看到现成的状态,输入jstack -l 进程id后可以看指定id的状态
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 22:40
 */
public class Run {
    public static void main(String[] args) {
        for(int i = 0; i<5; i++){
            new Thread(){
                @Override
                public void run() {
                    try {
                        Thread.sleep(500000);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }
}
  1. 利用官方工具jmc查看
  2. 利用工具jvisualvm查看

线程随机性的展现

package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 22:50
 */
public class MyThread2 extends Thread{
    @Override
    public void run() {
        for(int i =0; i<10000;i++){
            System.out.println("run="+Thread.currentThread().getName());
        }
    }
}
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 22:51
 */
public class Run2 {
    public static void main(String[] args) {
        MyThread2 thread2 = new MyThread2();
        thread2.setName("thread2");
        thread2.start();
        for (int i = 0; i < 10000; i++) {
            System.out.println("main=" + Thread.currentThread().getName());
        }
    }
}

通过输出可见,main和thread2两个线程随机打印

执行start()的顺序不代表执行run()的顺序

实现Runnable接口

package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:03
 */
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("运行中");
    }
}
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:04
 */
public class Run4 {
    public static void main(String[] args) {
        Runnable runnable =new MyRunnable();
        Thread thread =new Thread(runnable);
        thread.start();
        System.out.println("运行结束");
    }
}

使用Runnable接口实现多线程的优点

可以实现接口来达到“多继承”的功能

实现Runnable接口与继承Thread类的内部流程

实现Runnable接口法在执行过程上相比继承Thread法稍微复杂一些

实例变量共享造成的非线程安全问题与解决方案

  1. 不共享数据的情况
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:22
 */
public class MyThread3 extends Thread{
    private int count = 5;

    public MyThread3(String name) {
        super();
        this.setName(name);
    }

    @Override
    public void run() {
        super.run();
        while (count>0){
            count--;
            System.out.println("由"+ currentThread().getName()+"计算,count="+count);
        }
    }
}
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:26
 */
public class Run5 {
    public static void main(String[] args) {
        MyThread3 a = new MyThread3("A");
        MyThread3 b = new MyThread3("B");
        MyThread3 c = new MyThread3("C");
        a.start();
        b.start();
        c.start();
    }
}

从运行结果可见,他们的count值是非共享的,每个线程单独负责自己的count

由C计算,count=4
由A计算,count=4
由B计算,count=4
由A计算,count=3
由C计算,count=3
由A计算,count=2
由C计算,count=2
由B计算,count=3
由C计算,count=1
由A计算,count=1
由C计算,count=0
由B计算,count=2
由A计算,count=0
由B计算,count=1
由B计算,count=0
  1. 共享数据的情况
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:22
 */
public class MyThread4 extends Thread{
    private int count = 5;

    @Override
    public void run() {
        super.run();
        while (count>0){
            count--;
            System.out.println("由"+ currentThread().getName()+"计算,count="+count);
        }
    }
}
package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:30
 */
public class Run6 {
    public static void main(String[] args) {
        MyThread4 myThread4 = new MyThread4();
        Thread a = new Thread(myThread4,"A");
        Thread b = new Thread(myThread4,"B");
        Thread c = new Thread(myThread4,"C");
        Thread d = new Thread(myThread4,"D");
        Thread e = new Thread(myThread4,"E");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}

这样的话多个线程将会共用数据,因为不加锁,会导致一系列问题,改进方案如下:添加关键字synchronized在run()方法前

package mycode.chapter1;

/**
 * @author 29467
 * @date 2022/9/2 23:22
 */
public class MyThread4 extends Thread{
    private int count = 5;

    // 添加关键字synchronized
    @Override
    synchronized public void run() {
        super.run();
        while (count>0){
            count--;
            System.out.println("由"+ currentThread().getName()+"计算,count="+count);
        }
    }
}

Servlet技术造成的非线程安全问题与解决方案

多线程调用servlet会导致赋值时机错误问题,可在线程调用的servlet方法前添加synchronized关键字加锁解决


留意System.out.println()出现的非线程安全问题

println()方法在内部是同步的,作用范围仅限内部


currentThread()方法

返回代码段正在被哪个线程调用


isAlive()方法

判断当前的线程是否存活


sleep(long millis)方法

sleep()方法能让“正在执行的进程”休眠x毫秒


sleep(long million, int nanos)方法

毫秒+纳秒


StackTraceElement[] getStackTrace()方法

返回一个表示该线程的堆栈跟踪元素数组。第一个元素表示栈顶,是该数组中的最新方法调用,最后一个元素是栈底,表示最早的方法调用。


static void dumpStack()方法

将当前线程的堆栈跟踪信息输出至标准错误流。


static Map<Thread,StackTraceElement[]> geyAllStackTrace()方法

返回所有活动线程的堆栈跟踪的一个映射。


getId()方法

可以取得线程的唯一标识


停止线程

  1. interrupted():测试currentThread()是否已经中断,执行后具有清除状态标志值的功能
  2. isInterrupted():测试this关键字所在类的对象是否已经中断,不清除状态标志值

用stop()方法暴力停止线程

该方法并不能确定停止的位置,调用时会抛出java.lang.ThreadDeath异常,不需要显式捕捉。


使用stop()释放锁给数据造成不一致的结果


使用"return"语句停止线程的缺点与解决方案

多个判断条件下,使用return会导致代码冗余,推荐抛异常throw new InterruptedException()


暂停线程

使用suspend()方法暂停线程,使用resume()方法来恢复线程的执行。


suspend()方法与resume()方法的缺点—独占

在独占期间,其他线程无法访问


suspend()与resume()方法的缺点—数据不完整


yield()方法

yield()方法的作用是放弃当前的CPU资源,让其他任务去占用CPU执行时间,放弃的时间不确定


线程的优先级

优先级较高的线程获得的cpu资源更多,设置线程的优先级用setPriority()方法,优先级分为1-10个等级,超出范围会报错


线程优先级的继承特性

线程的优先级具有继承性,线程继承后优先级相同


优先级的规律性

优先级可以用setPriority()方法设置,cpu尽量给优先级较高的线程


优先级的随机性

优先级高的线程并不是先执行完毕


优先级对线程运行速度的影响

优先级高的运行速度快


守护线程

Java中分为用户线程(非守护线程),和守护线程
当进程中不存在非守护线程了,则守护线程自动销毁
凡是调用setDaemon(true)代码并且传入值的线程才是守护线程

相关文章:

  • 网课查题接口 该怎么搭建
  • Elasticsearch学习-- 聚合查询
  • 网课搜题公众号接口
  • ubuntu18.04.1LTS 编译安装ffmpeg详解
  • 接口幂等问题:redis分布式锁解决方案
  • 算法与数据结构(第一周)——线性查找法
  • 修改docker 修改容器配置
  • ARM汇编语言
  • 【通信】非正交多址接入(NOMA)和正交频分多址接入(OFDMA)的性能对比附matlab代码
  • 深入理解控制反转IOC和依赖注入
  • micropython 可视化音频 频谱解析(应该是全网首家)(预告,还没研究完成)
  • 网课答案接口平台 系统独立后台
  • stp基本介绍
  • 公众号如何接入查题功能
  • IDC_ISP网络之IDC机房内网络架构及配置
  • @jsonView过滤属性
  • 0基础学习移动端适配
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • HashMap ConcurrentHashMap
  • mysql 数据库四种事务隔离级别
  • python 装饰器(一)
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • SOFAMosn配置模型
  • Theano - 导数
  • 分布式熔断降级平台aegis
  • 高度不固定时垂直居中
  • 类orAPI - 收藏集 - 掘金
  • 扑朔迷离的属性和特性【彻底弄清】
  • 时间复杂度与空间复杂度分析
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #AngularJS#$sce.trustAsResourceUrl
  • #HarmonyOS:Web组件的使用
  • (八)Flask之app.route装饰器函数的参数
  • (分类)KNN算法- 参数调优
  • (七)Java对象在Hibernate持久化层的状态
  • (算法)Travel Information Center
  • (五)Python 垃圾回收机制
  • (一)基于IDEA的JAVA基础10
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .net 7 上传文件踩坑
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .Net中的设计模式——Factory Method模式
  • @JsonFormat与@DateTimeFormat注解的使用
  • @media screen 针对不同移动设备
  • @ResponseBody
  • [23] GaussianAvatars: Photorealistic Head Avatars with Rigged 3D Gaussians
  • [bzoj1324]Exca王者之剑_最小割
  • [C++]:for循环for(int num : nums)
  • [CCIE历程]CCIE # 20604