多线程介绍:

多线程是java中的一个并发的概念:
在计算机的运行中,所有的进程都是同时运行的(cpu会同时调用,之后随机的获取分配)

1.在java程序中也是支持的!
2.在java执行main方法的时候,其实就是执行一个名字叫做main的线程,可以在main线程执行的时候,开启多个其他的线程A,B,C等等,多个线程A,B,C等等都是同时执行的,同时等等cpu的调用,相互抢夺cpu调用自己的时间片段。
3.Thread类是java中的专门用于处理线程的api,是java.lang下的常用类,每一个Thread类的对象,
就代表一个某种状态的线程。

  • java.lang包下的常用的类有:String,System,八大基本类型,Thread…

  • 进程:表示一个个的正在运行的程序,比如qq,qq音乐,网易云…

  • 线程:表示一个个正在运行程序中的子进程(线程),qq的聊天窗口
  • 包含关系:一个进程包含多个进程
  • java中的线程是支持多线程的,多个线程可以同时进行,但是不能保证(控制)线程的运行,具体是看CPU的调用,我们只能看到结果。

java中使用Thread类来创建线程

第一种方式:

步骤:

  • 1.指定执行线程的目标:定义一个Thread子类,重写run方法,将相关的逻辑实现,public void run():将需要的逻辑写在里面,该方法相当于线程中的main方法。
  • 2.创建自定义线程的子类对象
  • 3.开启线程操作 - 触发

  • public void start():只要调用了这个方法,线程才会启动,开始执行

Thread中的相关方法:

  • public final String getName():获取线程的名称
  • public final void setName():设置线程的名字
  • public static Thread currentThread():获取当前的线程对象

image.png
线程的运行默认是不可控制的,是cpu随机调用,我们只能看到运行的结果。
**

  1. package ThreadDemo1;
  2. /**
  3. * 自定义线程类
  4. * 定义一个Thread的子类!
  5. *
  6. * 创建线程的第一种方式:继承Thread类
  7. */
  8. public class MyThread extends Thread{
  9. //重写run方法 - 相关的逻辑写进去
  10. @Override
  11. public void run(){
  12. for (int i = 0; i < 50; i++) {
  13. /*
  14. this表示当前正在被调用的这个线程
  15. 获取线程的名字是java干的事情(java定义的),我们不管,只要看就行了
  16. */
  17. System.out.println(this.getName()+":"+i);
  18. }
  19. }
  20. }
  1. package ThreadDemo1;
  2. public class ThreadDemo1 {
  3. //主线程
  4. public static void main(String[] args) {
  5. //创建线程对象 - 用于开启线程
  6. Thread t0 = new MyThread();
  7. Thread t1 = new MyThread();
  8. //开启线程 - 直接运行
  9. t0.start();
  10. t1.start();
  11. System.out.println("===========================");
  12. //返回一个main线程 - 其实就是main方法的线程
  13. Thread mainThread = Thread.currentThread();
  14. System.out.println(mainThread);//Thread[main,5,main]
  15. for (int i = 0; i < 50; i++) {
  16. System.out.println(mainThread.getName()+":"+i);
  17. }
  18. }
  19. }

start()方法的作用1.启动当前线程2.调用当前线程的run()

第二种方式:实现Runnable接口

  • 1.实现接口,并且要实现run方法
  • 2.在run方法中添加逻辑代码
  • 3.通过start启动线程
  • image.png ```java package ThreadDemo1;

/**

  • 创建线程的第二种方式: */ public class MyRunnable implements Runnable{

    @Override public void run() {

    1. //返回当前线程
    2. Thread thisThread = Thread.currentThread();

    } }

  1. **步骤:**
  2. - 1.指定线程执行的目标:定义Runnable接口,并且实现接口,重写run方法,指定目标逻辑
  3. - 2.通过指定线程执行目标的构造方法创建线程对象
  4. - public Thread(Runnable target)
  5. - 1)创建线程,并且执行目标对象
  6. - 2)通过线程执行目标对象创建线程对象
  7. - 3.开启线程操作(start
  8. **好处:将任务和线程相分离,耦合度比较低,使用也更加的广泛。**
  9. ```java
  10. package ThreadDemo1;
  11. /**
  12. * java中使用Thread类来创建线程:语法
  13. *第二种方式:
  14. *
  15. */
  16. public class ThreadDemo2 {
  17. //主线程
  18. public static void main(String[] args) {
  19. //创建线程执行目标
  20. MyRunnable mr = new MyRunnable();//线程对象 - 任务
  21. //通过指定线程执行目标的构造函数来创建线程
  22. Thread thread = new Thread(mr);//线程名称
  23. thread.setName("jack");
  24. Thread thread2 = new Thread(mr);//线程名称
  25. thread.setName("rose");
  26. //开启线程
  27. thread.start();
  28. thread2.start();
  29. }
  30. }

线程的优先级
image.png
说明:高优先级的线程要抢占低优先级线程的CPU执行权。但是只是 从概率上讲,高优先级的线程高概率
会被执行,并不意味着只有高优先级执行完后,低优先级才会执行。
**

匿名内部类创建线程 - 实际开发中使用

  • 1.使用匿名内部类创建线程的原理和普通类创建线程原理完全一样。
  • 2.区别在于利用匿名内部类创建线程的写法更加的简洁,使用非常多。 ```java package AnonysThread;

/**

  • 匿名内部类创建线程 - 实际开发中使用 *
  • 1.使用匿名内部类创建线程的原理和普通类创建线程原理完全一样。
  • 2.区别在于利用匿名内部类创建线程的写法更加的简洁,使用非常多。 / public class AnonysThreadDemo { public static void main(String[] args) {

    1. //方式一:使用匿名内部类创建线程的子类对象
    2. Thread t1 = new Thread(){
    3. @Override
    4. public void run(){
    5. System.out.println("我很好");
    6. }
    7. };
    8. t1.start();
    9. System.out.println("-----------------------------------------------");
    10. //使用匿名内部类,创建线程的匿名子类对象,并且启动线程
    11. new Thread(){
    12. @Override
    13. public void run(){
    14. System.out.println("还记得上次你我身旁的样子");
    15. }
    16. }.start();
    17. //方式二:使用匿名内部类的方式,创建执行目标类的对象
    18. Runnable r = new Runnable(){
    19. @Override
    20. public void run(){
    21. System.out.println("她来了然后他死了");
    22. }
    23. };
    24. //传入到构造函数
    25. Thread t2 = new Thread(r);
    26. t2.start();
    27. System.out.println("==========================================");
    28. //组合写法 - 精简写法
    29. new Thread(new Runnable() {
    30. @Override
    31. public void run() {
    32. System.out.println("往事只能后悔");
    33. }
    34. }).start();
    35. //t3的普通写法
    36. Thread t3 = new Thread(new Runnable() {
    37. @Override
    38. public void run() {
    39. System.out.println("往事只能后悔");
    40. }
    41. });
    42. t3.start();

    } }

  1. **线程的生命周期**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608015124063-999f19e7-e55f-4599-8452-cddb99ca800c.png#align=left&display=inline&height=255&margin=%5Bobject%20Object%5D&name=image.png&originHeight=510&originWidth=1194&size=248306&status=done&style=none&width=597)**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608039058241-07d5c2db-24ef-42cf-a39d-68afbe0c99fa.png#align=left&display=inline&height=218&margin=%5Bobject%20Object%5D&name=image.png&originHeight=435&originWidth=829&size=290722&status=done&style=none&width=414.5)**<br />**![](https://cdn.nlark.com/yuque/0/2020/png/2875088/1607995515730-951ca6d8-d924-4b09-bb0a-defab47232d8.png#align=left&display=inline&height=448&margin=%5Bobject%20Object%5D&originHeight=448&originWidth=828&status=done&style=none&width=828)<br />**线程的安全问题**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608040597262-7a557bba-5f93-47e1-8689-76a65f9e7034.png#align=left&display=inline&height=300&margin=%5Bobject%20Object%5D&name=image.png&originHeight=599&originWidth=999&size=272694&status=done&style=none&width=499.5)**<br />**在java中我们通过同步机制来解决线程的安全问题**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608041327859-e663d436-5eab-4d3c-b64b-f812f0d2f72b.png#align=left&display=inline&height=118&margin=%5Bobject%20Object%5D&name=image.png&originHeight=235&originWidth=712&size=155899&status=done&style=none&width=356)**<br />**要求:多个线程必须共用一把锁**<br />**同步方法**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608079587860-1b998fbf-738e-44c3-8d20-709cb1cada34.png#align=left&display=inline&height=90&margin=%5Bobject%20Object%5D&name=image.png&originHeight=179&originWidth=621&size=149124&status=done&style=none&width=310.5)**<br />**![image.png](https://cdn.nlark.com/yuque/0/2020/png/2879773/1608080422308-f1a740bd-0e86-4b78-bde9-fb3f6b0c6bbe.png#align=left&display=inline&height=40&margin=%5Bobject%20Object%5D&name=image.png&originHeight=80&originWidth=935&size=132311&status=done&style=none&width=467.5)**<br />** 说明:这三个方法只能出现在同步代码块和同步方法中**<br />**这三个方法的调用者必须是同步代码快或同步方法中的同步监视器**<br /> 实现callable接口创建线程
  2. ```java
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.FutureTask;
  6. /**
  7. * 创建线程的方式三:实现callable接口。------jdk5.0新增
  8. */
  9. //创建一个实现callable接口的实现类
  10. class CallableTest implements Callable {
  11. //实习call方法,将此线程需要执行的操作声明在call()方法中
  12. @Override
  13. public Object call() throws Exception {
  14. int sum=0;
  15. for (int i = 0; i <= 100; i++) {
  16. if(i%2==0){
  17. System.out.println(i);
  18. sum+=i;
  19. }
  20. }
  21. return sum;
  22. }
  23. }
  24. public class ThreadNew{
  25. public static void main(String[] args) throws ExecutionException {
  26. //创建callable接口实现类对象
  27. CallableTest callableTest = new CallableTest();
  28. //将次callable接口实现类对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
  29. FutureTask futureTask = new FutureTask(callableTest);
  30. //将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
  31. new Thread(futureTask).start();
  32. try {
  33. //获取callable中call方法的返回值
  34. //get()方法的返回值即为FutureTask构造器参数callcable实现类重写call()的返回值
  35. Object sum = futureTask.get();
  36. System.out.println("总和是" + sum);
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }

image.png
使用线程池创建线程
image.png
Executors:工具类,线程池工厂类,用于创建并返回不同类型的线程池
ExecutorService:真正的线程池接口

  1. class NumberThread implements Runnable{
  2. @Override
  3. public void run() {
  4. for (int i = 0; i <= 100; i++) {
  5. if(i%2==0){
  6. System.out.println(Thread.currentThread().getName()+":"+i);
  7. }
  8. }
  9. }
  10. }
  11. class NumberThread1 implements Runnable{
  12. @Override
  13. public void run() {
  14. for (int i = 0; i <= 100; i++) {
  15. if(i%2!=0){
  16. System.out.println(Thread.currentThread().getName()+":"+i);
  17. }
  18. }
  19. }
  20. }
  21. public class ThreadPoolTest {
  22. public static void main(String[] args) {
  23. //提供指定线程数量的连接池
  24. ExecutorService executorService = Executors.newFixedThreadPool(10);
  25. //设置线程池属性
  26. System.out.println(executorService.getClass());
  27. //执行指定线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
  28. executorService.execute(new NumberThread());//适合适用于Runnable
  29. executorService.execute(new NumberThread1());
  30. //executorService.submit();//适合使用于Callablle
  31. executorService.shutdown();//关闭连接池
  32. }
  33. }

image.png





**