多线程学习笔记

多线程

进程和线程

什么是进程

  1. 我们电脑中的每一个正在运行的程序都是一个进程,程序运行时系统就会创建一个进程,并为它分配资源。

请添加图片描述

  1. 线程:线程是一条执行路径,是程序执行时的最小单位,它是进程的一个执行流,比如qq可以开多个窗口,和多个人聊天,每个窗口就是一个线程。请添加图片描述

进程和线程的关系

一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

java中创建线程

继承Thread类

在java中,创建线程有3种方式。

1.继承Thread类,并且重写run方法,Thread类中的方法不是抽象方法,Thread类也不是抽象类

MyThread类继承了Thread之后,他就是一个线程类。要让线程启动。调用线程的start方法。

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("重写的run方法");
        System.out.println(2);
    }
}

public class Ch01 {
    public static void main(String[] args) {
        System.out.println(1);
        MyThread myThread=new MyThread();
        //当调用start方法启动一个线程时会执行重写的run方法的代码
        //调用的是start,执行的是run,为什么不直接调run
        myThread.start();
        //普通的对象调方法,没有启动线程
        //myThread.run();
        //线程的优先级,概率问题,做不到百分百
        //90%会先跑主方法,10%的几率会跑MyThread中的run方法
        System.out.println(3);
        System.out.println(4);
    }
}
输出结果
1
3
4
重写的run方法
2

2.实现Runnable接口

创建类实现Runnable接口,重写run()方法

class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println(2);
    }
}

public class Ch02 {
    public static void main(String[] args) {
        MyThread2 run=new MyThread2();
        //如果要想让线程启动,必须调用Thread类中的start方法
        //问题:实现了Runnable接口,找不到start方法了\
        //可以创建Thread对象,参数中传入Runnable接口或其实现子类
        Thread t=new Thread(run);
        t.start();
    }
}

实现Callable接口

创建类实现Callable接口,重写call()方法

class MyThread03 implements Callable<String>{
    @Override
    public String call() throws Exception {//
        System.out.println("2");
        return "call方法的返回值";
    }
}

public class Ch04 {
    public static void main(String[] args) {
        //Callable-->FutureTask-->RunnableFuture-->Runnable-->Thread
        System.out.println(1);
        FutureTask<String> futureTask=new FutureTask<>(new MyThread03());
        new Thread(futureTask).start();
        System.out.println(3);
        System.out.println(4);
    }
}

守护线程

守护线程
java中提供两种类型的线程
1.用户线程
2.守护程序线程

守护线程为用户线程提供服务,仅在用户线程运行时才需要。

守护线程对于后台支持任务非常有用。
垃圾回收,大多是jvm线程其实都是守护线程。

public class Ch05 extends Thread{
    public static void main(String[] args) {
        Ch05 ch05=new Ch05();
        ch05.setDaemon(true);//设置为true则为守护线程
    }
}

生命周期

NEW:这个状态主要是线程未被start()调用执行

RUNNABLE:线程正在JVM中被执行,等待来自操作系统的调度

BLOCKED:阻塞,因为某些原因不能立即执行,需要挂起等待。

WAITING:无限期等待。Object。如果没有唤醒,则一直等待。

TIME_WAITING:有限期等待,线程等待一个指定的时间

TERMINATED:终止线程的状态,线程已经执行完毕。

等待和阻塞这两个概念有点像,阻塞因为外部原因,需要等待
等待一般是主动调用方法,发起主动的等待,等待还可以传入参数,来确定等待时间。请添加图片描述

CPU多核缓存结构

CPU缓存为了提高程序运行的性能,现在CPU在很多方面对程序进行优化

CPU处理速度最快,内存次之,硬盘速度最低。

在CPU处理内存数据的时,如果内存运行速度太慢,就会拖累cpu的速度,为了解决这样的问题,CPU设计了多级的缓存策略。

CPU分为三级缓存:每个CPU都有L1,L2缓存,但是L3缓存是多级公用的。

CPU查找数据时,CPU->L1->L2->L3

从CPU到内存,60~80纳秒

从CPU到L3,15纳秒

从CPU到L2,3纳秒

从CPU到L1,1纳秒

寄存器,0.3纳秒

进一步优化,CPU每次读取一个数据,读取的是与它相邻的64个字节的数据
【缓存行】

英特尔提出了一个MESI协议

1.修改态,此缓存被动过,内容与主内存中不同,为此缓存专有

2.专有态,此缓存与主内存一致,但是其他CPU中没有

3.共享态,此缓存与主内存一致,其他的缓存也有

4.无效态,此缓存无效,需要从主内存中重新读取

线程安全的实现方法

线程安全的实现方法

1.保证数据不可变

​ 一切不可变的对象一定时线程安全的

​ 对象方法的事项方法的调用者,不需要在进行任何的线程安全的保障的措施

​ 比如说final关键字修饰的基本数据类型,字符串

​ 只要一个不可变的对象它能够正确的创建出来,外部的可见状态永远都不会改变

2.互斥同步,加锁。【悲观锁】

3.非阻塞同步【无锁编程】,自旋,我们会用cas来实现这种非阻塞状态

4.无同步方案:多个线程共享数据,这些数据又可以在单独的线程中计算的出结果,我们能可以把共享数据的可见
范围限制在一个线程之内,这样就无需同步了,把共享的数据拿出来,我用我的,你用你的,从而保证线程的安全
ThreadLocal

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值