javaSE复习之——线程

线程其实就是程序执行的一条路径,一个进程中可以包含多条线程,多线程并发执行可以提高程序效率,可以同使完成多项任务

多线程的应用场景

  • 迅雷多线程一起下载
  • 服务器同时处理多个客户请求

多线程原理(单核CPU)

在电脑上运行多个程序时,其实cpu一次只能做一个事,做一段时间后然后换另一个另一个做一段时间,只是cpu的速度太快了,看起来就是同时做很多事,也就是说多线程其实只是表面上的多线程,底层cpu还是一次只能做一个事,但是这有个前提,那就是那个cpu是单核cpu,如果事多核cpu,那么就可以真正的达到并行

多线程并行和并发的区别

  • 并行

    并行是两个任务同时运行,需要多核cpu,有多少核就可以并行多少任务。

  • 并发

    并发是两个任务都请求运行,而一个处理器只能接受一个任务,就安排两个任务轮流进行,由于时间比较段短就感觉两个任务是同时在运行

  • ps

    我们所谓的多线程就是并发,如果不使用多线程,那么程序就是一句一句代码请求,如果使用了多线程,那么就可以这个方法请求运行,同时另一个方法也请求运行,也就是说,没有使用多线程的话代码是一条一条请求,使用了就是多条同时请求,但底层并不是并行,只是cpu处理太快了感觉不到。

多线程程序实现方法1

1、定义类继承Thread

2、重写run方法

3、把新线程要做的事写在run方法中

4、创建线程对象,也就是我们定义的这个对象

5、开启新的线程(start),内部会自动执行run方法

多线程程序实现方法2

1、定义类实现Runnable接口

2、重写run方法

3、把新线程要做的事卸载run方法中

4、创建Thread对象,并且给它的构造方法传入一个实现了Runnable接口类的对象

5、利用Thread开启新的线程

多线程程序实现方法3

  • 第三种创建多线程的接口

    Callable

  • 创建方式:

    1、创建一个线程类,并且继承Callable<>类和重写call方法

    2、创建线程池

    3、创建线程对象然后用submit方法加入线程池即可

两种实现多线程的区别(面试可能问)

  • 继承Thread:

    因为我们创建的类继承了Thread类,所以当我们调用start时,是直接执行子类的run方法,也就是我们创建的类。

  • 实现Runnable接口创建对象并传入实例化Thread的构造方法:

    我们是先创建实现了Runnable接口的对象,然后创建Thread对象并把之前创建的对象传入Thread构造方法,这时Thread类会把传入的对象保存到成员变量中,当我们调用Thread对象的start方法的时候,Thread对象会调用它的成员变量中的run方法,当然这个成员变量就是我们创建的那个实现了Runnable接口的对象

两种实现多线程的好处与坏处

  • 继承Thread:

    • 好处:
      可以直接调用Thread中的方法,这样代码简洁。

    • 坏处:
      既然继承了Thread方法就不能继承其他类了

  • 实现Runnable接口:

    • 好处:
      因为接口是可以多实现的,所以可以继承其他父类

    • 坏处:
      不能直接创建对象使用,代码更加复杂

  • ps:

    个人感觉实现Runnable其实是继承Thread的一个补充,在开发时看情况使用。

Thread类的方法

  • .start()

    开启线程,多次启动是非法的

  • .getName()

    获取线程名,默认线程名从Thread -0开始以此类推

  • .setName()

    设置线程名

  • .c 大专栏  javaSE复习之——线程urrentThread()

    获取当前线程对象的引用,在哪调用就获取哪的线程

  • .sleep(毫秒, 纳秒)

    休眠线程,传入多少时间就停多长时间,也可以单独传毫秒

  • .setDaemon()

    守护线程,设置一个线程为守护线程后,该线程不会单独执行,当其他非守护线程全部执行完之后自动退出。

    • ps:
      在非守护线程全部执行完毕后,会有一个缓冲时间,这个缓冲时间内守护线程还会运行,也就相当于非守护线程退出时会告诉守护线程可以退出了,这个告诉的时间就是缓冲时间
  • .join()

    调用此方法的线程暂停(写这句代码的线程),等待指定线程结束后,当前线程再继续运行

  • .join(int)

    等待指定的毫秒后继续执行

    • ps:
      如果在main主方法中调用t.join(),那么等待t这个线程执行结束之后,主方法才会继续执行,这个命令通常用在主方法中。
  • .yield()

    礼让线程,让出cpu,也就是让自己在cpu的执行优先级中降低,就是让别人先执行

  • .setPriority(1-10)

    设置线程优先级,默认是5

  • .getThreadGroup()

    通过线程对象获取它所属的组,返回线程组对象

同步代码块的概述

当有多条线程并发的时候,cpu会先执行完同步代码块中所有代码才会去执行另一个线程,不会这里执行几句代码那里执行几句代码

  • ps:
    它其实就是锁

什么时候需要同步?

当多线程并发,我们希望某个线程中某些代码执行过程中不切换到其他线程工作,我们就需要用到同步代码块。

同步代码块关键字

synchronized

定义方式:

1
2
3
(锁对象) {
代码块
}

同步代码块(锁)的注意事项:

1、锁对象可以是任意的对象

2、两个需要同步的代码块需要使用同一个锁,否则不能达到目标效果

3、不能是匿名对象,因为两个匿名对象根本就不是一个对象,也就是不是同一把锁

4、不要把锁进行嵌套,否则容易出现死锁,因为可能会出现互相等待的局面

同步方法如何定义?

  • 解答:

    只要在修饰方法的时候加上synchronized关键字即可

同步方法注意事项:

  • 非静态方法锁对象是它自己这个对象,也就是this
  • 静态方法因为它是随着类的加载而加载的,所以它的对象就是它所在类的字节码文件,也就是说静态方法的锁对象就是它所在类的字节码文件

线程安全问题

当多条线程操作同一个数据时,可能会出现数据安全问题

  • 解决方法

    在某一段需要判断并且操作数据地方加上一个同步代码块

  • 注意事项

    使用的锁对象一定要是同一个锁,建议直接用类的class文件,如果非要用引用数据类型,那么一定要用静态的。

以前线程安全类的回顾

线程安全的类涉及数据操作的方法都加了synchronized修饰,比如Vector、ArrayList,StringBuffer、StringBuilde

线程安全方法

.synchronized[这里可以后接集合类型,是什么类型就返回那个类型的集合]

  • ps:
    它的作用是传入一个集合对象,传出一个线程安全的集合对象

猜你喜欢

转载自www.cnblogs.com/lijianming180/p/12041115.html