多线程基础知识!!!

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)

大家都在看

  • Transaction-Mybatis源码

    github地址:https://github.com/dchack/Mybatis-source-code-learn (欢迎star) TransactionFactory 官…

    Java 2023年6月14日
    097
  • JavaWeb_(视频网站)_四、博客模块2

    summernote富文本功能添加 前台submit-post-blog.html 上传图片到图文本框summernote中 修改后台通过Ajax上传图片请求 @RequestMa…

    Java 2023年5月29日
    070
  • Java基础之Synchronized原理

    思维导图svg: https://note.youdao.com/ynoteshare1/index.html?id=eb05fdceddd07759b8b82c5b9094021…

    Java 2023年5月29日
    076
  • zookeeper客户端之curator

    curator简介 curator是netflix公司开源的一个zk客户端 连接对象异步创建,需要开发人员自行编码等待 连接没有自动重连超时机制 watcher一次注册生效一次 不…

    Java 2023年6月8日
    089
  • SpringBoot整合Redis和SpringBoot(SpringCache)整合Redis

    参考博客: https://blog.csdn.net/lingerlan510/article/details/121906813 https://blog.csdn.net/u…

    Java 2023年6月6日
    064
  • 【转载】Spring AMQP中文文档

    http://ju.outofmemory.cn/entry/320538 Original: https://www.cnblogs.com/yingsong/p/9789377…

    Java 2023年5月29日
    088
  • Day13 note

    super注意点: 1、super调用父类的构造方法,必须在构造方法的第一行 2、super必须只能出现在子类的方法或者构造方法中 3、super和this不能同时调用构造方法对比…

    Java 2023年6月5日
    077
  • C语言-字符串函数的实现(五)之strstr

    C语言中的字符串函数有如下这些 获取字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strnc…

    Java 2023年6月10日
    060
  • 线程安全的 Set、List

    线程安全的Set: 综上可以看出,线程安全的 Set 底层选用 ConcurrentHashMap 的居多 线程安全的 List: Original: https://www.cn…

    Java 2023年5月30日
    0175
  • Java广度优先爬虫示例(抓取复旦新闻信息)

    以下内容仅供学习交流使用,请勿做他用,否则后果自负。 一.使用的技术 这个爬虫是近半个月前学习爬虫技术的一个小例子,比较简单,怕时间久了会忘,这里简单总结一下.主要用到的外部Jar…

    Java 2023年5月29日
    072
  • java8特性

    Lambda表达式 lambda表达式:本质就是一个函数式接口的实例对象。 语法: lambda&#x5F62;&#x53C2;&#x5217;&#…

    Java 2023年6月15日
    076
  • UML 活动图

    本学期在学 uml 建模,这星期要完成对项目用例图中几个主要用例的活动图分析,索性写下自己对活动图的学习笔记和实操。有些类似的用例,网上或者书上的活动图表示都不尽相同,我是按照自己…

    Java 2023年6月5日
    060
  • 网络编程

    网络编程 计算机网络是指将 地理位置不同的具有独立功能的 多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及 网络通信协议的管理和协调下, 实现资源共享和…

    Java 2023年6月6日
    095
  • 客观的聊一聊,裁员这件糟心事

    时间在走,环境在变,互联网有点卷不动了; 捋一捋最近互联网上关于职场的热点:裁员,优化,毕业,向社会输送人才,求职;你方唱罢他方登场,持续横跳热搜; 年初到现在五月底,身边已经有好…

    Java 2023年6月15日
    082
  • 碎碎念六一

    06.02 生活的乐趣在于造物。 造物从下厨始。 看见三只白色蝴蝶翩飞。花香引蝶。物以类聚。 06.03 走在路上,风轻云淡,日子宁静,如水涟漪。 读书,活动,吃饭,睡觉。 消减一…

    Java 2023年6月9日
    071
  • 接口回调与方法回调

    1.1 接口回调 简介:笔者查阅了大量资料,接口回调没有定义,可以理解为是一种设计思想。其本质是将 实现接口的类通过 向上转型至 接口类型,通过传入不同的子类,实现调用相应的 子类…

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