小工具      在线工具  汉语词典  css  js  c++  java

Java线程

Java,java 额外说明

收录于:152天前

进程与线程

过程
在操作系统中,每个独立的执行的程序都是一个进程,计算机上都是安装的多任务操作系统,能同时执行多个应用程序。

在多任务操作系统中,逻辑上它们是同时运行的,但实际上并非如此。所有应用程序均由CPU执行。对于CPU来说,一次只能运行一个程序。操作系统给每个进程分配有限的CPU占用时间,并且占用时间在同一个时间线上。

线
每个运行的程序都是一个进程,在一个程序中还可以有多个可执行的单元,每个单元称为线程。每个进程中至少存在一个线程。

当Java程序启动时,会生成一个进程,并创建一个线程来执行main函数的代码。代码会按照调用的顺序从上到下执行,称为单线程程序。如果想让程序多端的代码交替运行,就需要创建多个线程。

线程和进程由CPU执行,逻辑上在同一时间线上同时执行。

线程创建

Java中提供了两种多线程的实现方式,一种是继承java.lang包下的Thread类,重写run()方法,在run方法类实现线程代码;另一种方法是实现java.lang.Runable接口,重写run()方法。

继承线程

//继承Thread
import java.lang.Thread;
public class App {
    
    public static void main(String[] args) {
    
        MyThread myThread=new MyThread();
        myThread.run();
        for (int i=0;i<10;i++){
    
            System.out.println("main is running");
        }
    }

    static class MyThread extends Thread{
    

        @Override
        public void run() {
    
            for(int i=0;i<10;i++){
    
                System.out.println("MyThread is running");
            }

        }
    }
}

在这里插入图片描述

上面的代码演示了单线程的情况。 run是继承Thread创建的线程。线程结束后主程序结束。

多线程需要程序连续运行才能体现出来,系统分配CPU时间。

//多线程演示用start()方法,run会抢占线程
import java.lang.Thread;
public class App {
    
    public static void main(String[] args) {
    
        MyThread myThread=new MyThread();
        myThread.start();
        while (true){
    
            System.out.println("main is running");
        }
    }

    static class MyThread extends Thread{
    

        @Override
        public void run() {
    
            while (true){
    
                System.out.println("MyThread is running");
            }

        }

    }
}

在这里插入图片描述

如图看出两个线程是交替运行,由系统膏分配CPU占用时间。注意:用start()开启线程,不能用run()会抢占线程。

多线程和单线程的区别在于CPU时间的动态利用。单线程独占,多线程系统分配。

实现Runnable接口

Thread创建线程的缺点是必须继承Thread,已经有继承关系的类不能被继承(Java单继承原则)。 Runnable接口的优点是它只实现了Thread的run方法。只需要重写逻辑,将Runnable作为参数传递给Thread即可,不需要继承Thread。

//将Runnable作为参数传到Thread
public class App {
    
    public static void main(String[] args) {
    
        Thread thread=new Thread(new MyRunnable());
        thread.start();

        Thread thread1=new Thread(new MyRunnableOne());
        thread1.start();
    }

    static class MyRunnable implements Runnable{
    

        @Override
        public void run() {
    
            while (true){
    
                System.out.println("Runnable is running");
            }

        }
    }

    static class MyRunnableOne implements Runnable{
    

        @Override
        public void run() {
    
            while (true){
    
                System.out.println("RunnableOne is running");
            }

        }
    }
}

在这里插入图片描述

线程应用

Thread和Runnable都可以实现线程,那么有什么区别呢?

线程是独立的

class MyThreadOne extends Thread{
    
    private int total=100;
    @Override
    public void run() {
    
        while (total>=1){
    
            //获取当前线程
            Thread thread=Thread.currentThread();
            //获取线程名
            String th_name=thread.getName();
            System.out.println(th_name+"正在发售第"+total--+"张票");
        }
    }
}

public class MainApp {
    

    public static void main(String[] args) {
    
        MyThreadOne myThreadOne1=new MyThreadOne();
        MyThreadOne myThreadOne2=new MyThreadOne();
        MyThreadOne myThreadOne3=new MyThreadOne();
        myThreadOne1.start();
        myThreadOne2.start();
        myThreadOne3.start();
    }

}

代码实现了继承Thread,内部有100张票,三个线程发售。
在这里插入图片描述
由结果可以发现线程Thread-0和1,2都各自发售了第100次票,显然他们是独立的。

可运行线程是协作的

package com.company.runnable;

class MyRunnable implements Runnable{
    
    private int total=100;
    @Override
    public void run() {
    
        while (total>=1){
    
            //获取当前线程
            Thread thread=Thread.currentThread();
            //获取线程名
            String th_name=thread.getName();
            System.out.println(th_name+"正在发售第"+total--+"张票");
        }
    }
}

public class MainApp {
    
    public static void main(String[] args) {
    
        Thread myThreadOne1=new Thread(new MyRunnable());
        Thread myThreadOne2=new Thread(new MyRunnable());
        Thread myThreadOne3=new Thread(new MyRunnable());
        myThreadOne1.start();
        myThreadOne2.start();
        myThreadOne3.start();

    }
}

代码继承Runnable重写run方法,内部100张票
在这里插入图片描述
由结果可以看出所有线程共享成员变量。

除了上面案例外由多态特性也可以理解,通过实例化Thread创建是不同的对象,对象间是独立的,毫无关联的。而实现Runnable接口,仅仅是重写了run()方法,他们共享成员变量。

线程生命周期及状态转换

Java对象中的任何对象都有生命周期,线程也不例外。当Thread对象被创建时,线程的生命周期就开始了。当run抛出异常或阶段关闭时,线程结束。

线程的生命周期分为五个阶段:新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Termminate)。线程的不同状态表明该线程当前正在运行。活动。

  1. 新建状态
    JVM分配内存,没有任何线程特征。
  2. 就绪状态
    当线程调用start()方法后,线程进入就绪状态,线程位于线程队列中,等待CPU分配。
  3. 运行状态
    获得CPU使用权后执行线程执行体,该程序处于运行状态。系统剥夺CPU使用权后,处于等待状态,等待再次占有CPU,直至程序结束。
  4. 阻塞状态
    运行的线程由于某种原因,被迫让出CPU使用权而进入阻塞状态。此时线程并没有进入等待对列,CPU由其他等待对列中的线程使用,直至解除阻塞状态,进入等待对列,等待系统分配CPU使用权后才能再次执行。
    notify()和·wait()方法可以使线程进入阻塞状态。sleep()方法使阻塞特定时间,join()加入新进程会阻塞原进程,直至新进程运行完毕。

线程调度

程序的多个线程在逻辑上是并发的。一个线程想要执行,就必须获得CPU的所有权。 Java虚拟机按照特定的机制为线程分配CPU的使用权,这种机制称为线程调度。

线程调度有两种模型:分时调度和抢占式调度。分时调度是指按照执行线上同一维度的时间片轮流分配CPU的使用权。抢占式调度按照优先级分配CPU使用权。

线程优先级
Java JVM默认是抢占式调度,优先级决定了CPU分配顺序。
在这里插入图片描述
图中大写的常量设置线程优先级。

线程休眠
sleep(long millis)方法让线程休眠一段时间把CPU让给其他线程。该方法时静态方法,只能控制当前的线程休眠,休眠结束后,该线程进入等待对列。

螺纹优惠
线程让步时正在执行的线程将CPU让给其他线程,yield()方法。

线程队列跳转
线程可以通过join()方法在某个线程之前执行。

线程安全
多线程共享资源时由于延迟或其他原因导致的错误。

class MyRunnable implements Runnable{
    
    private int total=5;
    @Override
    public void run() {
    
        while (total>=1){
    
            //获取当前线程
            Thread thread=Thread.currentThread();
            //获取线程名
            String th_name=thread.getName();
            //添加延迟
            try {
    
                Thread.sleep(10);
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
            System.out.println(th_name+"正在发售第"+total--+"张票");
        }
    }
}


public class MainApp {
    
    public static void main(String[] args) {
    
        Thread myThreadOne1=new Thread(new MyRunnable());
        Thread myThreadOne2=new Thread(new MyRunnable());
        Thread myThreadOne3=new Thread(new MyRunnable());
        myThreadOne1.start();
        myThreadOne2.start();
        myThreadOne3.start();

    }
}


代码模拟了10毫秒的延迟,线程执行的进度是不一样的。
在这里插入图片描述
由于线程都有10毫秒的休眠,出现了很多重复的情况。

Java提供了同步机制,当多个线程使用同一个共享资源时将执行共享资源的代码放在synchronized关键字修饰的代码块中,这个代码块被称作同步代码块。

synchronized 返回值类型 方法名([参数列表]){代码块}

synchronized (obj){
    
    while (total>0){
    
        //获取当前线程
        Thread thread=Thread.currentThread();
        //获取线程名
        String th_name=thread.getName();
        //添加延迟
        try {
    
            Thread.sleep(10);
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        }
        System.out.println(th_name+"正在发售第"+total--+"张票");
    }
}
. . .

相关推荐

额外说明

C++ 中的智能指针 auto_ptr 解析

c++中的auto_ptr是一个类,却可以像指针一样去使用。使用auto_ptr需要包含头文件#include <memory> 例如:auto_ptr<string> ps(new string("hello"));可以像指针一样去使用它,可以这样co

额外说明

一线城市,北上广深装不下的远方,二线城市,或许是更好的选择?

英国散文家洛根·皮尔索尔·史密斯曾经说过:对一个职业的考验在于,你是不是热爱当中的苦役。 真实世界里极少有不经修饰就感天动地的励志故事,有的不过是在日复一日平凡的工作里,一次次和懒惰、欲望博弈,最终总能选择逆着人性,精进自己。 今天的主人公Bob的故事,

额外说明

对象是否存活,可以这样判断?

首先说为什么要判断是否存活,当垃圾收集器在对堆进行回收前,第一就是要确定对象哪些是还在被引用的或者后面还需要被引用的,即存活,哪些是已经“死去”(即不可能再被任何途径使用) 1、引用计数算法 在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就

额外说明

并查集模板+应用(图文并茂,保你看懂)

-音乐分享(点击链接可以听哦)  平凡之路_朴树   并查集是一种树型的数据结构,用于处理一些不相交集合(DisjointSetsDisjointSets)的合并及查询问题。常常在使用中以森林来表示。  836. 合并集合 - AcWing题库    

额外说明

Java案例:根据速度计算刹车的安全距离

文章目录 一、提出任务 二、知识点 三、完成任务 (一)编写程序,实现功能 (二)运行程序,查看结果 一、提出任务 说明:在高速公路驾驶的场景下,比如在限速每小时120千米的路段,人类驾驶员需要的刹车距离为210m。这段距离主要包含:在2.5s内(驾驶员

额外说明

【第14篇】TextCNN

摘要 我们报告了在预训练词向量之上训练的卷积神经网络 (CNN) 的一系列实验,用于句子级分类任务。 我们表明,具有很少超参数调整和静态向量的简单 CNN 在多个基准测试中取得了出色的结果。 通过微调学习特定于任务的向量可进一步提高性能。 我们还建议对架

额外说明

二级VB培训笔记10:知识点串讲

二级VB培训笔记10:知识点串讲 一、对象概述 1、三大特性:封装性、继承性、多态性 参看《VB讲课笔记1202. 二级公共基础 - 程序设计基础》 2、对象的属性 了解VB对象的常用属性 3、对象的方法 了解VB对象的常用方法 4、对象的事件 了解VB

额外说明

手摸手带你 在Windows系统中安装Istio

Istio简介 通过负载均衡、服务间的身份验证、监控等方法,Istio 可以轻松地创建一个已经部署了服务的网络,而服务的代码只需很少更改甚至无需更改。 通过在整个环境中部署一个特殊的 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务

额外说明

如火如荼的「云原生」,你了解多少?

        人类璀璨浩瀚的科技发展历程中,每一个宏观与微观领域都离不开计算的参与。计算机的出现,让我们从发现到解决问题的速度呈指数级增长,极大加快了创造的效率。         云计算,是结合人类社会顶端智囊与最尖端 IT 科技而诞生的最新互联网技术

额外说明

C语言枚举变量知识回顾

C语言枚举变量知识整理 1.枚举变量的声明 1.1.与结构体的声明类似,成员变量间用, 而不是用;。下面代码为声明时不对成员赋初始值的声明语句 //声明枚举类型color,它的可能值为:red、green、yellow 枚举颜色 { 红色的, 绿色的,

ads via 小工具