首页 > 编程语言 >关于Java中多线程

关于Java中多线程

时间:2023-06-07 18:35:20浏览次数:43  
标签:Java Thread -- System 线程 关于 println 多线程 public

基本概念

什么是进程-->是操作系统资源分配和调度的最小(基本)单位(操作系统分配给当前进程一个内存区域供其使用)

什么是线程-->是程序运行的基本单位(等待操作系统分配时间片 让CPU执行该内存区域中的代码)

进程和线程的关系-->一个进程可以存在多个线程 线程是由进程创建的(寄生在进程中) 线程是进程中一个负责程序执行的控制单元

什么是单线程-->只处理一个任务

什么是多线程-->宏观上同时处理多个任务即并发执行也就是说允许单个进程运行多个线程来完成不同的任务(站在CPU角度微观上其实1个CPU每时刻只能执行一个任务 但是宏观上看这CPU一会执行这个一会执行那个)

谈谈线程的几种状态-->开始(new)-->就绪(runnable)-->运行(runnint)-->阻塞(blocked)-->销毁(dead)

多线程有什么好处-->异步处理任务 将IO任务异步(阻塞IO线程让其他线程进入开始状态)操作提高CPU利用率

多线程有什么缺点-->线程也是程序当线程越来越多会导致占用内存大 多线程需要协同管理需要跟棕栈 线程之间对共享资源的访问必须解决竟用的问题 线程太多会导致程序过于复杂难以排除bug

一个java程序至少有几个线程-->当我们启动java程序的时候会立即执行main()方法这个线程被称为程序的主线程和垃圾回收线程

聊聊Java中的多线程

java.util.concurrent简称JUC

实现多线程的方式-->调用Thread.start()方法

  • 重写Runnable接口中的run()方法 实例化Runnable接口实现类并作为参数传递给Thread
  • 继承Thread类并重写run()方法 实例化继承类
  • 重写Callable接口中的call()方法产生的回调结果参数传递给FutureTask()构造函数然后将实例对象作为参数传递给Thread构造函数

怎么开启一个线程-->不管通过哪种方式实例化Thread的时候 线程就到开始状态了

什么是初始态-->仅仅在语言层面创建一个线程实例

怎么到就绪态-->调用Thread.start()方法 线程进入就绪态等待操作系统分配时间片

怎么到运行态-->操作系统分配时间片给当前线程

怎么从运行态回到就绪态-->时间片用完还没有完成任务那么就又回到就绪态

怎么从运行态到阻塞态-->进行耗时的IO操作时 操作系统拿到其时间片将其分配给其他线程 或者Thread.sleep()方式强制进入睡眠状态

怎么从阻塞态回到就绪态-->在阻塞态的线程完成其操作回到就绪队列中等待操作系统分配时间片

怎么从运行态到销毁-->线程中的代码执行完毕然后jvm收回线程占用的资源!

什么是主线程-->Main线程 垃圾回收线程

怎么让线程停止-->Thread类提供stop()方法用于停止一个已启动的线程但本质是不安全的

如何安全停止一个正在运行的线程-->线程对象在执行完run()方法所有代码执行完成后线程会自然消亡因此需要在运行过程提前停止线程 可以通过更改变量值的方法run()方法提前结束

创建线程的三种方式

public class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println("操作系统分配时间片给我啦!");
    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("操作系统分配时间片给我啦!");
    }
}
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "操作系统分配时间片给我!!";//产生一个返回结果
    }
}

测试类

public class TestCreate {
    @Test
    public void test1() throws Exception{
        MyRunnable myRunnable = new MyRunnable();
        //创建线程
        Thread t1=new Thread(myRunnable,"实现runnable接口的方式");
        MyThread t2=new MyThread("继承thread的方式");
        MyCallable myCallable = new MyCallable();
        FutureTask<String> futureTask=new FutureTask<>(myCallable);
        Thread t3 = new Thread(futureTask);//futureTask负责调用call()函数
        t3.setName("我是实现Callable的方式");
        t1.start();
        t2.start();
        t3.start();
        String s = futureTask.get();//通过get方式拿到返回的结果
        System.out.println("这里是返回的结果-->"+s);
    }
}

线程中断

打断正在执行的线程

  • Thread实例.stop()方式

stop方式会杀死一个进程 如果此时该线程锁住了一些共享资源 那么它被杀死以后就再也没有机会释放锁 其他线程将永远无法获取锁

  • System.exit(int)方式停止线程

目的是停止一个线程 但这样会让整个程序都停止!

打断被堵塞的线程

  • 两阶段终止模式
public class MonitorThread{
    //维护一个Thread实例 来监控是否被打断
    private Thread monitor;
    public void start(){
        monitor=new Thread(()->{
            while (true){
                //isInterrupted不会清除打断标记
                if (monitor.isInterrupted()){
                    System.out.println("料理后事...");
                    break;
                }
                try {
                    //每次5秒1记录
                    Thread.sleep(5);
                    System.out.println("监控记录");
                }catch (InterruptedException e){
                    e.printStackTrace();
                    System.out.println(monitor.isInterrupted());//false
                    monitor.interrupt();//重置打断变量
                }
            }
        });
        monitor.start();
    }
    //停止监控线程
    public void stop(){
        monitor.interrupt();
    }

    public static void main(String[] args) throws InterruptedException {
        MonitorThread monitorThread = new MonitorThread();
        monitorThread.start();
        Thread.sleep(100);
        monitorThread.stop();
    }
}

守护线程

主线程执行完毕-->守护线程无论是否执行完毕就dead

守护线程-->垃圾回收器 tomcat中的分发器

public static void main(String[] args) throws InterruptedException {
    Thread t1=new Thread(()->{
        while (true)
            System.out.println("我是daemon线程...");
    });
    //设置为守护线程
    t1.setDaemon(true);
    t1.start();//线程不可以多次执行start()方法
    Thread.sleep(10);
    System.out.println("主线程准备结束--守护线程也被挂掉了");
}

烧水喝茶

graph LR; a(洗水壶1分钟)-->b(煮水15分钟)-->c(泡茶叶) d(洗茶壶 拿茶叶 洗茶叶 4分钟)-->c
public static void main(String[] args) {
    //两个线程模拟烧水喝茶的过程
    Thread t1=new Thread(()->{
        try {
            System.out.println("水壶清洗...");
            Thread.sleep(1000);
            System.out.println("烧水...");
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    });
    Thread t2=new Thread(()->{
        try {
            System.out.println("洗茶壶");
            Thread.sleep(1000);
            System.out.println("拿茶叶");
            Thread.sleep(2000);
            System.out.println("洗茶叶");
            Thread.sleep(1000);
            t1.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("泡茶ok");
    });
    t1.start();//小王
    t2.start();//小张
}

共享带来的问题

一个程序运行多个线程本身是没有问题的 但问题出在多个线程访问共同的资源

//全局变量2个线程访问
public class Test3 {
    static int global=0;
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
           for (int i=0;i<2500;i++){
               global++;
           }
        });
        Thread t2=new Thread(()->{
            for (int i=0;i<2500;i++){
                global--;
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //为什么执行2500次g++和2500次g--结果并不一定是0 字节码角度分析
        // 自增自减运算符并非一条指令(非原子操作)
        System.out.println(global);
    }
}

在一个线程中

临界区

标签:Java,Thread,--,System,线程,关于,println,多线程,public
From: https://www.cnblogs.com/odfive/p/17464221.html

相关文章

  • java 接口
    为什么使用接口接口可以实现java中的“多继承”什么是接口接口的关键字是interface接口中的所有方法都是用抽象abstract修饰的;没有方法体;那个类要用这个接口就在那个类中写接口中的方法接口不能实例化,接口就是抽象的概念实现类中必须实现接口中的所有方法实现的关键字imple......
  • java多态
    多态的定义:父类引用指向子类对象实现多态的三个要素:1.编写具有继承关系的父类和子类publicclassDemoextendsTest2.子类重写父类方法重写的定义是子类和父类拥有相同方法名或者相同属性的方法3.使用父类的引用指向子类的对象符合这三个条件就可以使用多态多态的向上转......
  • java面试(30)- redis
    1:Redis支持的数据类型a)字符串keyvalb)hashkeynamefiledc)listkeyv1v2v3v3d)setkeyv1v2v3d)zsetkeysv2:Redis支持的事务3:为什么redis快 4:redis的优缺点1、优点a)数据类型丰富b)支持数据......
  • JAVA——时间类
    JAVA——时间类世界标准时间格林尼治时间简称GMT目前世界标准时间已替换为:原子钟中国标准时间:世界标准时间+8小时 时间单位换算1秒=1000毫秒1毫秒=1000微秒1微秒=1000纳秒 如何创建对象?Datedate=newDate();Datedate=newDate(指定毫秒值);如何修改时间......
  • java中基本数据类型和包装数据类型
    基本数据类型和包装数据类型在Java中有着重要的区别和联系,对于Java程序员来说,熟悉这两种数据类型的特点和使用方法是非常必要的。 基本数据类型 Java中的基本数据类型一共有8种,分别为:-byte-short-int-long-float-double-char-boolean基本数据类型是指可以......
  • java微信公众号 推送消息
    WxConfig.java @Slf4j@ServicepublicclassWxConfig{@ResourceprivateWxClientwxClient;//appIdprivatestaticfinalStringappId="xxxx";//appIdSecretprivatestaticfinalStringappIdSecret="xxxx";privatestat......
  • java代码调用Python代码
    1,使用runtime调用Python脚本String[]arguments=newString[]{"E:\\ProgramFiles\\python.exe","E:\\wzCode\\signal.py",Arrays.toString(datas),String.valueOf(Num)};......
  • 关于安科瑞智能通讯管理机在能源计量行业的应用-安科瑞张田田
    建筑能耗应用场景描述在电力监控系统能源计量中经常会运用到通信管理机,通信管理机也称作DPU,其具有多个下行通讯接口及一个或者多个上行网络接口,相当于前置机,即监控计算机,用于将一个变电所内所有的智能监控/保护装置的通讯数据整理汇总后,实时传送至上级主站系统(后台监控中心系统和DCS......
  • Java7新特性: 多异常捕获
    在Java7中引入了一种新的异常处理机制,即多异常捕获。在之前的版本中,我们通常使用单个catch块来捕获所有可能抛出的异常。但是,这种方式可能导致代码变得冗长且难以阅读。多异常捕获机制可以使代码更加简洁、易读,并且可以更准确地处理不同类型的异常情况。接下来就让我们大家一起来看......
  • 关于CloudFront-Distribution-SSL-证书过期的更新替换操作记录
    提前说明:载止今天,AWSCloudFront还是只支持IAM类型的证书今天笔者主要讲述当AWSCloudFrontDistribution的SSL证书过期后,如何进行更新1、假定已经知道某个CloudFrontDistribution使用的SSL证书将要过期2、进入CloudFrontDistributions页面,找到指定的Distribution,  ......