多线程基础知识!!!



1.1、继承Thread类(重点)

public class MyThread extends Thread{
    @Override
    public void run() {

    }

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
    }
}
  • 通过继承Thread类,然后重写run方法实现多线程
  • 通过在main方法中调用实现了Thread类的对象的start方法
  • 线程不一定立即执行,而是有CPU调度
  • 不建议使用,避免oop单继承的局限性

1.2、实现Runnable接口(重点,推荐)

public class MyThread1 implements Runnable{
    @Override
    public void run() {

    }

    public static void main(String[] args) {
        MyThread1 myThread1=new MyThread1();
        new Thread(myThread1).start();
    }
}
  • 通过实现Runnable接口,然后重写接口的run方法
  • 通过在main方法中new一个Thread对象,然后将实现了Runnable接口的类的对象当做参数传入Thread构造方法,再调用Thread对象的start方法
  • 本质上来说这两种方式都是一样的,因为Thread类也实现了Runnable方法,而继承Thread类就相当于实现了Runnable接口
  • 推荐使用,方便同一个对象被多个线程调用

1.3、实现Callable接口(了解)

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class MyCallable implements Callable {
    private int flag=1;
    @Override
    public String call() throws Exception {
        Thread.sleep(10);
        return "你好"+flag++;
    }

    public static void main(String[] args) {
        MyCallable myCallable=new MyCallable();
        Future future=null;
        List> list=new ArrayList<>();
        ExecutorService service= Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            future=service.submit(myCallable);
            list.add(future);
        }
        try {
            for (int i = 0; i < 10; i++) {
                String str1=list.get(i).get();
                System.out.println(str1);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        service.shutdownNow();
    }
}
  • 通过实现Callable接口,重写call方,该方法与run方法不同,run方法没有返回值而call有
  • 重写call方法时需要抛出异常
  • 创建实现了Callabl接口的类的对象
  • 通过ExecutorService service=Executors.newFixedThreadPool(10)方法创建执行服务,参数为线程的个数
  • 通过service.submit(myCallable)提交执行,并返回一个Future<>类型的结果,参数为实现了Callabl接口的类的对象
  • 通过Future<>对象的get方法获取返回的结果
  • 最后通过ExecutorService 的对象的shutdownNow()方法关闭服务

  • Thread.currentThread().getName()–拿到当前线程的名字,Thread.currentThread()表示当前线程

public void run() {
    System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket--+"张票");
}
  1. Thread.sleep(int)–线程休眠指定的时间,单位毫秒
try {
    Thread.sleep(20);
} catch (InterruptedException e) {
    e.printStackTrace();
}

注:
– 使用该方法可以模拟网络延时,放大问题以便让我们观察到
– 使用该方法还可以模拟倒计时
– 该方法不会释放锁
3. new Thread(myThread1,”小明”)–构造函数,第二个参数为线程的名字

public static void main(String[] args) {
    MyThread1 myThread1=new MyThread1();

    new Thread(myThread1,"小明").start();
    new Thread(myThread1,"小红").start();
    new Thread(myThread1,"小东").start();
}
  1. join()–相当于插队,必须该线程执行完才能张执行其他的线程
public class Yield implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i==0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("插队线程======="+i);
        }
    }

    public static void main(String[] args) {
        Yield yield1=new Yield();
        Thread thread1=new Thread(yield1);
        thread1.start();

        for (int i = 0; i < 500; i++) {
            if(i==200){
                try {
                    thread1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main线程======"+i);
        }
    }
}
  1. yield()–暂停当前线程,并执行其他线程,也叫做礼让线程
public class Yield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束执行");
    }

    public static void main(String[] args) {
        Yield yield1=new Yield();
        new Thread(yield1,"a").start();
        new Thread(yield1,"b").start();
    }
}

注:
– 礼让不一定成功,相当于重新竞争
6. interrupt()–中断线程,不建议使用这种方式
7. isAlive()–测试线程是否处于活动状态
8. getStates()–得到线程的状态

Yield yield1=new Yield();
Thread thread1=new Thread(yield1);
System.out.println(thread1.getState());
thread1.start();
System.out.println(thread1.getState());
for (int i = 0; i < 10; i++) {
    System.out.println(thread1.getState());
    if(i==200){
        try {
            thread1.join();
            System.out.println(thread1.getState());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(thread1.getState());
    System.out.println("main线程======"+i);
}
}
  • [NEW]
    尚未启动的线程处于此状态。
  • [RUNNABLE]
    Java虚拟机中执行的线程处于此状态。
  • [BLOCKED]
    被阻塞等待监视器锁定的线程处于此状态。
  • [WAITING]
    正在等待另一个线程执行特定动作的线程处于此状态。
  • [TIMED_WAITING]
    正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
  • [TERMINATED]
    已退出的线程处于此状态。
  • 线程停止方法:
  • 建议让线程正常终止,利用次数,不建议死循环
  • 建议使用一个标志位,去设置一个flag
  • 不要使用stop(),destory()等过时或者jdk不建议的方法
  • 线程的优先级
  • getPriority()–得到线程的优先级
  • setPriority(int)–设置线程的优先级 注:
  • 主线程的优先级不能更改,使用默认的优先级5
  • 先设置优先级再启动
  • 优先级大只是被调用的概率大,不一定优先级高的就先被调用
  • 优先级范围为1~10
  • 守护线程:线程分为用户线程和守护线程,JVM必须等待用户线程执行完成,而不必等待守护线程进行完毕,通过setDaemon(true)设置线程为守护线程,默认为false

5.1、了解线程同步

问题:当多个线程访问一个资源的时候,就会出现线程不安全的问题,导致资源的变化出现不一致!!

解决:通过锁和队列的机制解决

具体:

  • 每一个对象都有一个锁,线程必须拿到该对象的锁才可以对该资源进行操作
  • 当有多个线程访问同一个对象时,就会形成一个队列
  • 当线程访问该对象的时候,如果该对象有锁,那么线程拿到对象的锁
  • 后续线程按照一定的顺序去访问这个对象,访问的时候会去检查该对象是否有锁,如果没有则说明上一个线程还没有操作完毕,也就是还没有释放该对象的锁,即该等待的线程还不能操作该对象

弊端:

  • 虽然解决了安全的问题,但是使用锁以及排队会降低性能
  • 如果出现优先级高的线程等待优先级低的线程,那么可能会出现优先级倒置的情况

5.2、代码模拟

5.3、Lock锁

5.4、死锁

产生情况:当有多个线程相互拿着对方资源,并且需要获得对方的资源才能释放锁的时候,就会产生死锁,因为都需要彼此的资源来释放自己的资源,导致资源一直不能被释放进而程序卡死,出现死锁的情况!!!

死锁的四个必要条件

解决死锁的4种基本方法

Original: https://www.cnblogs.com/xiaoye-Blog/p/16608220.html
Author: 小也取不到名字
Title: 多线程基础知识!!!

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/590014/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Git 使用入门

    学习之前,要明白一个概念: 版本控制 什么是版本控制 版本迭代,新的版本,需要版本管理器 版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或…

    Java 2023年6月9日
    029
  • Hystrix 断路器

    分布式系统面临的问题:复杂分布式体式结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败。 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务…

    Java 2023年6月8日
    026
  • java笔记

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年9月21日
    0153
  • spring的循环依赖

    1 单例 bean 构造器参数循环依赖(⽆法解决)2 prototype 原型 bean循环依赖(⽆法解决)对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过set…

    Java 2023年5月30日
    029
  • Elasticsearch 入门实战(5)–Java API Client 使用

    本文主要介绍 Elasticsearch Java API Client 的使用,相关的环境及软件信息如下:CentOS 7.6.1810、Java 1.8.0_321(客户端用)…

    Java 2023年6月16日
    029
  • 常用Dos命令

    文件夹上面的路径换成cmd 进入控制台,并且控制台的路径,也就是当前的文件夹cmd地方的文件路径管理员方式运行Cmd 此电脑搜索cmd –>命令提示符 &#821…

    Java 2023年6月6日
    032
  • php: 单下划线函数意义

    待完善参考 posted @2022-09-21 09:42 CodeWater 阅读(10 ) 评论() 编辑 Original: https://www.cnblogs.com…

    Java 2023年6月7日
    032
  • MySQL中IN()按照指定列指定规则排序

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月7日
    028
  • 【校招VIP】高校大学生自己的商业项目|产品脑图的重要性:活动模型的细节分析

    ​哈喽大家好,今天来看一下真实的商业项目——约起来课程。今天讲解产品的第二期,脑图的第二部分。本节课针对上节课的四个问题进行难点分析: 今天的重点脑图的过程,最终版的官方脑图提供下…

    Java 2023年6月5日
    036
  • SpringCloud系列之使用Feign进行服务调用

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年9月22日
    0146
  • 快速上手Spring项目

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年11月10日
    0100
  • 使用7z程序CLI实现基础功能

    阅文时长 | 0.64分钟字数统计 | 1025.6字符主要内容 | 1、引言&背景 2、压缩 3、解压 4、更多命令可见 5、声明与参考资料『使用7z程序CLI实现基础功…

    Java 2023年6月5日
    031
  • Java导出带格式的Excel数据到Word表格

    注入产生的原理: 数据库设置为GBK编码: 宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而…

    Java 2022年11月10日
    0144
  • 算法设计与分析———分治算法

    一、分治法的设计思想 分治法将一个难以直接解决的大问题划分为一些规模较小的子问题,分别求解各个子问题,再合并子问题的解得到原问题的解。 分治法的典型情况 二、分治法的求解过程 一般…

    Java 2023年6月5日
    040
  • 从零开始实现放置游戏(九)——实现后台管理系统(7)地图选择控件

    前面做了地图怪物的添加,删除,查询等功能。但添加怪物的时候,需要选择怪物所在地图。前几张的源代码中,我忘了把这部分改回去,所以如果想要成功添加,需要自己改一下html界面,手动填写…

    Java 2023年6月5日
    036
  • ArrayList扩容机制

    写在前面 数据结构在面试中基本都是常问的,但是一般开发中基本上都是在使用没有去关心过怎么实现的。 在数据结构中,链表是一种线性存储结构,也就是常说的线性表。 概念:线性表,是数据结…

    Java 2023年6月5日
    031
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球