首页 > 编程语言 >十、Java多线程

十、Java多线程

时间:2023-11-09 21:01:14浏览次数:50  
标签:执行 Java Thread void 线程 run 多线程 public

一、多线程概述

1、进程: 正在运行的程序,是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。

2、线程: 是进程中的单个顺序控制流,是一条执行路径 一个进程如果只有一条执行路径,则称为单线程程序。 一个进程如果有多条执行路径,则称为多线程程序。

3、Java程序运行原理 java 命令会启动 java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。在此之前的所有程序都是单线程的。

4、jvm虚拟机的启动是多线程的。  主线程与垃圾回收线程

二、多线程实现

java提供了一个类描述线程 Thread,一个JVM中可以创建多个线程同时执行,每个线程都有优先权
java中创建线程对象的几种方式:


1、自己写一个A类继承Thread类,重写run方法,这个A类就叫线程类
注意:
1、run方法就是一个线程对象要做的事情
2、线程对象不能靠调用run方法来启动线程,只能算普通的对象调用了一个普通的方法,和线程没关系了。
3、要想启动一个线程,应该调用start()方法来进行启动,JVM进程中会为这个线程开辟一个对象,这个线程内部调用对应的run方法
4、调用完start()方法之后,线程只是具备了执行的资格,但是还没有真正的执行,只有抢到了CPU执行权的时候,才会执行(执行run方法里面的逻辑,run方法执行完了,线程也就结束了)

Thread类构造方法:
Thread() 分配一个新的 Thread对象。
Thread(String name) 分配一个新的 Thread对象。

Thread类中的成员方法:
public final String getName() 获取当前线程的名字
public final void setName(String name) 将此线程的名称更改为等于参数name 。
public static Thread currentThread() 获取当前方法所在的线程 主线程的名字叫做main
package com.shujia.day15;
class MyThread1 extends Thread {
    MyThread1(){
        super();
    }

    MyThread1(String name){
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            System.out.println(getName()+" -- "+i);
//            System.out.println("--------------------------"+currentThread().getName()+"--------------------------");
        }
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
//        MyThread1 t1 = new MyThread1(); // 在使用无参构造方法的时候,给创建的对象起了名字
//        t1.setName("AAA");
//        MyThread1 t2 = new MyThread1();
//        t2.setName("BBB");
//        //启动线程
////        t1.run();
////        t2.run();
//        t1.start();
//        t2.start();

        //使用带参数的构造方法,在创建线程对象的时候给线程起名字
        MyThread1 t1 = new MyThread1("AAA");
        MyThread1 t2 = new MyThread1("BBB");
        t1.start();
        t2.start();

        System.out.println("--------------------------"+Thread.currentThread().getName()+"--------------------------");
    }
}

2、自己写一个A类实现Runnable接口,实现run方法,这个A类就叫线程类

             实现接口方式的好处:可以避免由于Java单继承带来的局限性。 适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。

 
package com.shujia.day15;

/*
    第二种实现线程方式:自己写一个A类实现Runnable接口,实现run方法,这个A类就叫线程类,需要借助Thread类来创建线程对象
 */
class MyRunnable implements Runnable{
    //
    @Override
    public void run() { // 线程要执行的逻辑在run方法中编写
        for (int i = 1; i <= 200; i++) {
            //因为第二种是实现了Runnable接口,接口中只有一个抽象的run方法,找不到getName()方法,所以报错
            //如果想要在这里输出线程的名字的话,可以间接地获取当前线程对象,然后再获取线程名字
            System.out.println(Thread.currentThread().getName()+" -- "+i);
        }
    }
}

public class MyRunnableDemo1 {
    public static void main(String[] args) {
        //如何创建线程对象并启动呢?
        MyRunnable myRunnable = new MyRunnable();

        //需要借助Thread类来创建线程对象 public Thread(Runnable target)
//        Thread t1 = new Thread(myRunnable);
//        Thread t2 = new Thread(myRunnable);
//        Thread t3 = new Thread(myRunnable);
//        t1.setName("大哥");
//        t2.setName("二哥");
//        t3.setName("三弟");

        //public Thread(Runnable target, String name) 创建线程对象的同时给线程起名字
        Thread t1 = new Thread(myRunnable, "大哥");
        Thread t2 = new Thread(myRunnable, "二哥");
        Thread t3 = new Thread(myRunnable, "三第");

        //启动线程
        t1.start();
        t2.start();
        t3.start();

    }
}

 



3、自己写一个A类实现Callable接口,实现call方法,这个A类就叫线程类,需要结合线程池才能使用

                好处: 可以有返回值 可以抛出异常 弊端: 代码比较复杂,所以一般不用

三、线程的调度

1、线程有两种调度模型:

分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。

Java使用的是抢占式调度模型。

2、线程的优先级

每个线程都有优先级。

默认情况下,线程的优先级都是5,优先让优先级高的线程使用CPU

public final int getPriority() 获取线程的优先级

public final void setPriority(int newPriority) 修改线程的优先级 范围是[1,10]

注意:优先级高的线程只是说先执行的概率会大一些,并不是一定会先执行。

四、线程控制

线程休眠:public static void sleep(long millis)  毫秒

线程加入: public final void join()   其他线程会等待该线程执行结束

线程礼让 public static void yield() 

后台线程 public final void setDaemon(boolean on)

后台线程(守护线程):
线程分为两种:
用户线程:是没有设置Daemon的线程
守护线程:当没有用户线程的时候守护线程自动死亡

中断线程 public final void stop()

     public void interrupt()

                             线程的生命周期图

 

五、解决线程安全问题

首先想为什么出现问题?(也是我们判断是否有问题的标准)

是否是多线程环境

是否有共享数据

是否有多条语句操作共享数据

基本思想:让程序没有安全问题的环境

实现:把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可

具体实现:

①:同步代码块 :
      格式: synchronized(对象){需要同步的代码;}

  同步的前提

    多个线程

    多个线程使用的是同一个锁对象

  同步的好处: 同步的出现解决了多线程的安全问题。

    同步的弊端 :当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

 ②同步方法 就是把同步关键字加到方法上

    如果锁对象是this,就可以考虑使用同步方法。 否则能使用同步代码块的尽量使用同步代码块。

 解决线程安全问题的第二种方案:使用Lock锁来实现

但是通过观察API后发现,Lock本身是一个接口,所以找一个实现类:ReentrantLock

    void lock() 加锁
void unlock() 释放锁

死锁的问题:

同步弊端 效率低 如果出现了同步嵌套,就容易产生死锁问题

死锁问题及其代码 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象 同步代码块的嵌套案例


六、线程中的通信 
代码改进:A:通过等待唤醒机制实现数据依次出现
         B:把同步代码块改进为同步方法实现
                              线程的状态转换图

    

 

七、线程组
概述:Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
    默认情况下,所有的线程都属于主线程组。
     public final ThreadGroup getThreadGroup()
    我们也可以给线程设置分组
    Thread(ThreadGroup group, Runnable target, String name)
    直接对组进行操作,也会影响到组中的线程,有了线程组,方便管理和分类
 
八、线程池 Executors
概述:程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池

线程池的分类:
tatic ExecutorService newCachedThreadPool() 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
static ExecutorService newSingleThreadExecutor() 创建一个使用从无界队列运行的单个工作线程的执行程序。
static ExecutorService newFixedThreadPool(int nThreads) 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。

注意:
线程一旦被放入了线程池中就会开始执行(相当于调用了start()方法,具备了执行资格);
线程池中的线程之间会互相抢CPU执行权;
线程池需要手动关闭,一般情况下需要不断地放入线程执行,一般不需要关。

 九、定时器   
概述:定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
构造方法:Timer() 创建一个新的计时器。
方法:
void schedule(TimerTask task, long delay)  在指定的延迟之后安排指定的任务执行。  
void schedule(TimerTask task, long delay, long period) 在指定的延迟之后开始 ,重新执行固定延迟执行的指定任务。

十、设计模式 
概述:设计模式:是历代程序员开发总结得出的经验,并被后人持续的使用
分类:
创建型模式
简单工厂模式:
              简单工厂模式(一个工厂中可以造很多的各种各样的对象)
              这个模式的缺陷是如果有新的对象的话,需要修改很多类,而一般情况下,工厂类不轻易修改
        工厂方法模式:每一个对象都由自身的一个工厂创建出来
        单例模式:指的是在程序运行过程中,类内存中有此仅有一个对象
            懒汉式
饿汉式
        面试的时候说懒汉式,开发的时候使用饿汉式。因为懒汉式有可能存在线程安全的问题。懒汉式写的时候需要加上synchronized关键字
    行为型模式
结构型模式
 简单工厂模式(一个工厂中可以造很多的各种各样的对象)
这个模式的缺陷是如果有新的对象的话,需要修改很多类,而一般情况下,工厂类不轻易修改


 
    
 

  
 
 
 
 

标签:执行,Java,Thread,void,线程,run,多线程,public
From: https://www.cnblogs.com/SIKE231310/p/17818196.html

相关文章

  • Java中的IO流(一)
    Java中的IO流(一)一、前言学习这部分内容的时候,跟着敲代码难免有些乱,这里先放一张图:二、实现对文件和文件夹的操作:案例一:packagefile.bytestream;importjava.io.File;importjava.io.FileNotFoundException;importjava.io.IOException;publicclassFileDemo1{......
  • Java中的多态
    向上转型后的再向下转回去才行注意:向下转型时,有可能编译阶段不报错,但是程序运行时会报错,类型转换异常。......
  • Java中的抽象类
    注意:抽象类中也是有默认的无参构造函数的eg:抽象类中的构造方法父类publicabstractclass_168AbstractParent{privateintage=300;privatefinalintcode_200=200;public_168AbstractParent(){System.out.println("我是Parent的无参构造方法......
  • 每天5道Java面试题(第6天)
    1. 接口和抽象类有什么区别?默认方法实现:抽象类可以有默认的方法实现;接口不能有默认的方法实现。实现:抽象类的子类使用构造函数:抽象类可以有构造函数,接口不能有。main方法:抽象类可以有main方法,并且我们能运行它;接口不能有main方法。实现数量:类可以实现很多个接口;但是只能继承......
  • Java登陆第二天——SQL之DML
    SQL语句SQL概括起来可以分为以下四组。(都是SQL,因为功能的不同,为了更好学习划分了类别)DDL——数据定义语言。用于定义数据的结构。指的是增,删,改数据库DML——数据操作语言。用于检索或修改数据。指的是增,删,改数据DQL——数据查询语言。用于查询各种形式的数据。指的是查询......
  • 商城系统 “牵手” 淘宝 API 接口 php java sdk
    随着互联网的快速发展,网络购物已成为人们日常生活中不可或缺的一部分。淘宝作为中国最大的电商平台之一,其商城系统中详情页面的重要性日益凸显。本文将阐述淘宝详情在商城系统中的重要性,从用户角度、商家角度和商城运营角度进行分析,并探讨如何优化详情页面,提升用户转化率和购物体验......
  • 【Java Web】从配置修改静态变量
    对象@ConfigurationProperties(prefix="system-upload-prefix")@Configuration@RefreshScope@DatapublicclassSystemUploadPrefix{privateStringupload;}修改常量@ComponentpublicclassConstants{@AutowiredSystemUploadPrefixsystemU......
  • 封装java导出Excel工具类使用
     基于POI的导入导出工具类使用背景快速引入基本excel导入成对象合并excel导入成为对象导出复杂excel表格最后 背景自己封装了一个excel工具类,方便以后使用和部分可能有相同需求的朋友使用,现在做一个简单的记录快速引入第一步导包,maven包仅包含poi依赖,导入时注......
  • 封装java导出Excel工具类使用(二)
    目录背景快速引入基本excel导入成对象和合并excel导入成为对象导出基本excel表格注:本次更新的列表1对多样式同样适用于导出异形表中的列表最后背景自己封装了一个excel工具类,方便以后使用和部分可能有相同需求的朋友使用,现在做一个简单的记录快速引入第一步导包,maven包仅包含......
  • IDEA (JAVA) 内存使用高堆分析
    ====================HISTOGRAM====================Histogram.Top50byinstancecount[All-objects][Only-strong-ref]:1:[2.0M/141MB][1.75M/127MB]byte[]2:[1.99M/43.8MB][1.74M/38.3MB]java.lang.String3:[421K/15.1MB][369K/13.2MB]java.util.H......