首页 > 编程语言 >java多线程

java多线程

时间:2024-07-19 23:55:34浏览次数:12  
标签:java Thread class start 线程 new 多线程 public

程序,进程,线程,并行,并发

  • 程序是静态的,进程process是动态的
  • 一个进程至少有一个线程
  • 多线程程序优点
    • 提高应用程序的响应
    • 提高CPU利用率
    • 改善程序结构
  • 并行parallel,指两个或多个事件在同一时刻发生
  • 并发concurrency,两个或多个事件在同一个时间段内发生,宏观上是多个进程同步进行

创建和启动线程

JVM允许程序运行多个线程,java.lang.thread代表线程。所有的线程对象都必须是Thread类或其子类实例。

创建线程的方式:

  • 1、继承Thread类
  • 2、实现Runnable接口

创建线程方式1示例

public class EvenNumberTest {
    public static void main(String[] args) {

        PrintNumber printNumber = new PrintNumber();
        printNumber.start(); // 启动线程,调用当前线程的run(),即子类重写的run()方法
    }
}


class PrintNumber extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++){
            if ( i % 2 == 0) System.out.println(i);
        }
    }
}
  • 获取当前线程的名称:Thread.currentThread().getName()

  • 一条路径就是单线程。

  • 不能用run()代替start()方法,start()要先启动线程,创建一个新的线程。

  • 不能让已经start()的线程,再次执行start()操作。

创建线程方式2示例

public class EvenNumberTest {
    public static void main(String[] args) {
        EvenNumberPrint t1 = new EvenNumberPrint();
        new Thread(t1).start();

    }
}


class EvenNumberPrint implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++){
            if (i % 2 == 0) System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }
}

创建方式1,方式2的区别

共同点:

  • 启动线程,使用的都是Thread类中定义的start()
  • 创建的线程对象,都是Thread类或其子类的实例。

不同点:一个是类的继承,一个是接口的实现。

建议:建议使用实现Runnable接口的方式。

Runnable方式的好处:
① 实现的方式,避免的类的单继承的局限性
② 更适合处理有共享数据的问题。
③ 实现了代码和数据的分离。

联系:public class Thread implements Runnable (代理模式)

Thread类常用方法和生命周期

构造器

  • public Thread() :分配一个新的线程对象。
  • public Thread(String name) :分配一个指定名字的新的线程对象。
  • public Thread(Runnable target) :指定创建线程的目标对象,它实现了Runnable接口中的run方法
  • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

public Thread(String name)示例

public class EvenNumberTest {
    public static void main(String[] args) {
        EvenNumberThread t1 = new EvenNumberThread("线程1");// 相当于给线程命名
        t1.start();

        

    }
}

class EvenNumberThread extends Thread{

    public EvenNumberThread(){

    }

    public EvenNumberThread(String name){
        super(name);
    }
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++){
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

线程常用方法

  • start():①启动线程 ②调用线程的run()
  • run():将线程要执行的操作,声明在run()中。
  • currentThread():获取当前执行代码对应的线程
  • getName(): 获取线程名
  • setName(): 设置线程名
  • sleep(long millis):静态方法,调用时,可以使得当前线程睡眠指定的毫秒数
  • yield():静态方法,一旦执行此方法,就释放CPU的执行权
  • join(): 在线程a中通过线程b调用join(),意味着线程a进入阻塞状态,直到线程b执行结束,线程a才结束阻塞状态,继续执行。
  • isAlive():判断当前线程是否存活

线程的优先级

每个线程都有一定的优先级,同优先级线程组成先进先出队列,使用分时调度。优先级高的采用抢占式策略。

每个线程的默认优先级与创建他的父线程具有相同的优先级。

  • getPriority():获取线程的优先级
  • setPriority():设置线程的优先级。范围[1,10]

Thread的三个优先级常量:

  • MAX_PRIORITY(10),最高优先级
  • MIN_PRIORITY,最低优先级
  • NORM_PRIORITY,普通优先级

生命周期

JDK1.5之前,5中状态

在这里插入图片描述

之后

阻塞分的更细
在这里插入图片描述

同步代码块解决两种线程创建方式的线程安全问题

示例及原因

同一个资源问题和线程安全问题。模拟车站售票,实现多个窗口同时售票。不能出现错票,重票。
下面的实现,是一个线程不安全的问题。两种实现线程方式都会出现重票,错票的情况。

public class WindowTest {
    public static void main(String[] args) {
        // 创建对象
        SaleTicket s = new SaleTicket(); // 创建一个对象,被三个线程所共享
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);
        // 创建三个窗口
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

//        SaleTicket1 t2 = new SaleTicket1();
//        t2.start();
    }
}

原因是当前进行的线程还没结束,其他线程也参与进来,对ticket进行操作。

解决办法

必须保证一个线程a在操作ticket的过程中,其它线程必须等待,直到线程a操作ticket结束以后,其它线程才可以进来继续操作ticket。

这里ticket共同操作的数据,即共享数据。

java解决方式

使用线程的同步机制。

两种方式:

  • 同步代码块
  • 同步方法
    本质上是一样的。

同步代码块

synchronized(同步监视器){
    //需要被同步的代码
}

说明:

  • 需要被同步的代码,即为操作共享数据的代码。
  • 共享数据:即多个线程都需要操作的数据。比如:ticket
  • 需要被同步的代码,在被synchronized包裹以后,就使得一个线程在操作这些代码的过程中,其它线程必须等待。
  • 同步监视器,俗称锁。哪个线程获取了锁,哪个线程就能执行需要被同步的代码。
  • 同步监视器,可以使用任何一个类的对象充当。但是,多个线程必须共用同一个同步监视器。
使用接口runnable

在实现Runnable接口的方式中,同步监视器可以考虑使用:this


public class WindowTest {
    public static void main(String[] args) {
        // 创建对象
        SaleTicket s = new SaleTicket(); // 创建一个对象,被三个线程所共享
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);
        // 创建三个窗口
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

//        SaleTicket1 t2 = new SaleTicket1();
//        t2.start();
    }
}

// 接口方式
class SaleTicket implements Runnable{
    Integer tickets = 100;

    Object obj =  new Object();

    @Override
    public void run() {
//        System.out.println(Thread.currentThread().getName() +":卖票");
        while (true){
            // 增加休眠时间
            try{
                Thread.sleep(5);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            synchronized(obj){ // 可直接用this,也代替对象
				// 这里面如果添加sleep也是锁住进程的
                if (tickets > 0){
                    System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets);
                    tickets --;
                }else break;
            }
        }

    }
}
继承Thread

如果监视器使用this,则每个线程会有一个监视器,不能保证锁的唯一性。

在继承Thread类的方式中,同步监视器要慎用this,可以考虑使用:当前类.class

public class WindowTest {
    public static void main(String[] args) {
        // 创建对象


        SaleTicket1 t2 = new SaleTicket1();
        SaleTicket1 t3 = new SaleTicket1();
        SaleTicket1 t4 = new SaleTicket1();
        t2.setName("窗口2");
        t3.setName("窗口3");
        t4.setName("窗口4");
        t2.start();
        t3.start();
        t4.start();
    }
}

class SaleTicket1 extends Thread {
    static int tickets = 100;
    static Object obj = new Object(); // 加上static,静态唯一的

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (obj) {// 实际上也是对象class clz = 当前类.class 
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets);
                    tickets--;
                } else break;
            }

        }
    }
}

同步方法

如果操作共享数据的代码完整的声明在了一个方法中,那么我们就可以将此方法声明为同步方法即可。

  • 非静态的同步方法,默认同步监视器是this。
  • 静态的同步方法,默认同步监视器是当前类本身。

使用接口runnable

先将同步代码块中的需要被同步的代码用方法进行封装,此时还是同步代码块。


class SaleTicket2 implements Runnable{
    Integer tickets = 100;

    Object obj =  new Object();

    Boolean isFlag = true;
    @Override
    public void run() {
//        System.out.println(Thread.currentThread().getName() +":卖票");
        while (isFlag){
            // 增加休眠时间
            try{
                Thread.sleep(5);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            synchronized(obj){

               show();
            }
        }

    }

    public void show() {
        if (tickets > 0){
            System.out.println(Thread.currentThread().getName() + "售票,票号为:" + tickets);
            tickets --;
        }else{
            isFlag = false;
        }
    }
}

标签:java,Thread,class,start,线程,new,多线程,public
From: https://blog.csdn.net/Misnearch/article/details/140521758

相关文章

  • 在 Java 中,怎样设计一个可扩展且易于维护的微服务架构?
    在Java中设计一个可扩展且易于维护的微服务架构,可以考虑以下几个方面:模块化设计:将应用拆分为多个小的、独立的模块,每个模块负责处理特定的业务逻辑。每个模块可以独立开发、测试和部署,增加或替换模块时不会影响其他模块。使用轻量级的通信机制:微服务之间通过RESTfulAPI......
  • JAVA面试框架篇(SSM和MyBatis)
    框架篇一.Spring1.Spring1.1Bean生命周期1.2Bean循环依赖(引用)说说spring中的循环引用构造方法出现了循环依赖怎么解决?1.3Bean线程安全问题问题:Spring中的Bean是线程安全的吗?1.4AOP(什么是AOP?)AOP:AspectOrientedProgramming面向切面编程应用场景(你们项目中有没有......
  • 初级java每日一道面试题-2024年7月19日
    在Java中,重载(Overloading)和重写(Overriding)是面向对象编程中多态性的两个重要概念。1.重载(Overloading)定义:重载是指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。也就是说,这些方法的名称相同,但参数的个数、类型或顺序至少有一个不同。目的:重载......
  • javaScript常用对象
    1. Array对象JavaScriptArray对象用于定义数组1.1定义格式数组的定义格式有两种:方式1var变量名=newArray(元素列表);例如:vararr=newArray(1,2,3);//1,2,3是存储在数组中的数据(元素)方式2var变量名=[元素列表];例如:vararr=[1,2,3];//1,2,3是......
  • JavaWeb学习笔记后端部分
    后端Web开发MavenApacheMaven是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。Maven作用依赖管理统一的项目结构项目构建仓库安装Maven<mirror><id>alimaven</id><name>aliyunmaven</name><url>h......
  • Java入门基础:Java中的标识符;Java常量与变量;Java基本数据类型;Java运算符
    一,Java标识符【1】标识符:读音 biaozhifu (注意是标zhi符,不是标shi符,“识”这个字是多音字,我也是才发现^_^,你呢?)【2】标识符是?     包,类,变量,方法.....等等,只要是起名字的地方,那个名字就是标识符。【3】标识符定义规范:  1.四个可以(组成部分):数字,字母,下划......
  • Java基础-详解String类
    为什么String类是不可变的publicfinalclassString{privatefinalchar[]value;}由以上String类的源码可以看出,String类内部使用字符数组char[]来存储字符串(Java9后修改为byte[]字节数组),而且数组被final修饰且为私有的,String类没有提供修改该字符串方法,以及由于S......
  • Javaweb项目|电子商城购物平台的设计与开发+ssm小程序
    Javaweb项目|电子商城购物平台的设计与开发+ssm小程序收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示 基于电子商城购物平台的设计与开发+ssm小程序开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat......
  • JavaScript 异步编程:提升现代Web应用的性能与体验
    异步概念解析在编程领域,异步(Asynchronous)是一种允许程序继续执行而不等待某个操作完成的机制,与之相反的是同步(Synchronous),其中程序会暂停并等待每个操作完成才继续下一步。异步编程的核心优势在于提高了应用程序的响应性和资源利用率。想象一下,你正在厨房准备晚餐,同步操作......
  • Java毕业设计基于Vue+SpringBoot体育竞赛成绩管理系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录项目介绍技术介绍项目界面关键代码目录项目介绍体育竞赛是各种体育体育项目比赛的总称。是在裁判员的主持下,按统一的规则要求,组织与实施的体育员个体或体育队之间的竞技较量,是竞技体育与社会发生关联,并作用于社会的媒介,随着......