2022-8-2第一组孙乃宇 多线程

多线程

进程和线程

什么是进程

  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

 
posted @   孙乃宇  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示