多线程基础

多线程的一些基础

    java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流(一段顺序执行的代码)。java使用线程执行体来代表这段程序流。

 

 一、进程和线程的定义和区别

    进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。

    线程:进程内部的一条执行路径或者一个控制单元。

    两者的区别:一个进程至少有一个线程,进程在执行过程中拥有独立的内存单元,而多个线程共享内存。

     多线程并行和并发的区别:

    * 并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
    * 并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。

    多线程:一个进程中有多个线程,称为多线程(默认是指并发)

二、实现多线程的方法:实现多线程可以通过继承Thread类实现Runnable接口

方法一:继承Thread类创建线程类

        通过继承Thread类来创建并启动多线程的步骤如下:

            1:定义Thread类的子类,并重写该类的run()方法,该方法的方法体就代表了线程需要完成的任务。因此把run()方法称为线程执行体。

            2:创建Thread子类的实例。即创建了线程的对象。

            3:调用线程对象的start()方法来启动线程。

  (ps.关于一些疑问这里边的一些疑问,讲完第二种实现多线程的方法在统一来解决。)

//通过继承Thread类实现多线程
public class ThreadDemo extends Thread {
  private int count=0;//系统访问次数
  public void run() {
      count++;
      System.out.println("第"+count+"位访客来啦!");
  }
  public static void main(String[] args) {
      ThreadDemo rd=new ThreadDemo();
      for(int i=0;i<50;i++){
          Thread thread=new Thread(rd);
          thread.start();//一定要注意不是通过.run()启动线程
      }
  }
}

方法二:实现Runnable接口创建线程类

    实现Runnable接口来创建并启动多线程的步骤如下。

        1:定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

        2:创建Runnable实现类的实例,并以此实例作为Threadtarget来创建Thread对象,该Thread对象才是真正的线程对象

        3:调用线程对象的start()方法来启动该线程

//通过Runnable接口实现多线程
public class RunnableDemo implements Runnable{
  private int count=0;//系统访问次数
  @Override
  public void run() {
      count++;
      System.out.println("第"+count+"位访客来啦!");
  }
  public static void main(String[] args) {
      RunnableDemo rd=new RunnableDemo();
      for(int i=0;i<50;i++){
          Thread thread=new Thread(rd);
          thread.start();//一定要注意不是通过.run()启动线程
      }
  }
}

 

 

 

 

回答上边可能会产生的疑问:

①为什么运行结果每次都不同?

       因为多个线程都获取CPU的执行权,CPU执行到谁,谁就运行。需要注意的是:在某一个时刻,只能有一个程序在运行。(多核CPU除外只不过是CPU在做着快速切换,已达到看上去是同时运行的效果。 我们可以形象的把多线程的运行看作是在互相抢夺CPU的执行权这是CPU的一个特性:随机性。谁抢到CPU的资源谁就执行,至于运行多长时间,CPU说了算。(如果要使多线程实现同步:可以再run()方法前边加上synchronized(中文 叫:同步锁),举个栗子:public synchronized void run() {......}

 

②为什么要覆盖Run方法?

        Thread类用于描述线程。该类就定义了一个功能(方法),用于存储线程要运行的代码,该存储功能就是run方法。run()方法中的内容称为线程体,它就是这个线程需要执行的工作。

 

③为什么要调用线程对象的start()方法?start()和run()方法有什么区别?

       调用start方法方可启动线程,而run方法只是thread的一个普通方法,调用run方法不能实现多线程。

       start()方法:

       start()方法用来启动线程,实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片(执行权),就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。

       run()方法:

       run()方法只是Thread类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。

start()方法和run()方法区别对比:https://blog.csdn.net/kwame211/article/details/79030255

 

 此外可以了解一下:

java5提供了Callable接口,该接口怎么看看都像是Runable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更加强大。

1call()方法可以有返回值

2call()方法可以声明抛出异常

因此完全可以提供一个Callable对象作为Threadtarget,而该线程的线程执行体就是该Callable对象的call()方法。问题是,Callable接口是java5新增的接口,而且它不是Runnable接口的子接口。所以Collable对象不能直接作为Threadtarget.而且call()方法还有一个返回值,call方法并不是直接调用,他是作为线程执行体被调用的那么如何获取call()的返回值呢?

jiava5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个实现类FutureTask。该实现类实现了Future接口,并实现了Runnable接口。可以作为Thread类的target.

Callable接口有泛型的限制,Callable接口里的泛型形参类型与call()方法的返回值类型相同。而且Callable接口是函数式接口,因此可使用Lanbda表达式创建Callable对象。

创建并启动有返回值的线程步骤如下:

1:创建Callable接口的实现类,并实现call()方法,该方法将作为线程执行体,且该方法有返回值,再创建Callable实现类的实例。

2:使用FutureTask类包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值

3:使用FutureTask对象作为Thread对象的target创建并启动新线程

4:调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

 

 

 

1:多线程
(1)多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序
线程:进程的执行单元,执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径

多进程的意义?   提高CPU的使用率

多线程的意义?   提高应用程序的使用率

(2)Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVMJVM会启动一个进程,该进程会启动一个主线程。

 

B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。

(3)多线程的实现方案(自己补齐步骤及代码掌握)
A:继承Thread

 

 

B:实现Runnable接口

(4)线程的调度和优先级问题
A:线程的调度
    a:分时调度
    b:抢占式调度 (Java采用的是该调度方式)
B:获取和设置线程优先级
    a:默认是5
    b:范围是1-10
(5)线程的控制(常见方法)
A:休眠线程
B:加入线程
C:礼让线程
D:后台线程
E:终止线程
(6)线程的生命周期
A:新建
B:就绪
C:运行
D:阻塞
E:死亡


多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
A:是否有多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据

 

同步解决线程安全问题
A:同步代码块
synchronized(对象) {
需要被同步的代码;
}

这里的锁对象可以是任意对象。

B:同步方法
把同步加在方法上。

这里的锁对象是this

C:静态同步方法
把同步加在方法上。

这里的锁对象是该类的字节码(比如Demo.class)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值