[JavaEE]什么是线程?

一 线程

1.1线程的概念

• 进程:操作系统分配资源的基本单位,程序的一次执行过程就是进程,每一个进程都有独立的内存空间,点开一个程序从运行到关闭即代表了进程的创建,运行,和销毁。
• 线程:操作系统调度的基本单位,线程(轻量级进程)是包含在进程当中的,每一个进程包括多个线程(至少有一个线程)每一个线程都是独立执行流,一个进程里面的多个线程是并发执行的。

1.2 进程与线程

进程的创建,销毁,和切换需要频繁的申请,释放,切换内存空间,这对于系统来说是比较大的时间开销,所以引入了线程这一概念。
在操作系统中,线程属于比较抽象的内容,所以我采取图片和举例子的方式来解释线程,图解:
在这里插入图片描述
如果把一个进程比作一个工厂,在资金不足(对应系统资源不足)的情况下,你想同时生产多种配件(对应一个应用程序的多种功能,如QQ里面视频,通话等等),如果采取不断新建工厂(在内存中为一个程序的多个功能一一申请创建进程)的方式,既耗费资源(内存)又耗费时间(系统效率)。所以我们想到了另外一种方法,在工厂内共享生产设备(多个线程共享进程的内存、文件描述符表)来开设多个流水线完成不同配件的生产,由于流水线之间有很强的关联性(一个流水线停止运行,可能导致其他流水线不能运转),比如手机组装厂,当屏幕生产的流水线出现问题后,组装手机的流水线可能就会停止运作,从而导致整个工厂停止。

总结:
1.进程包含线程。
2.进程有自己的独立内存和文件描述表,一个进程的多个线程共享进程的内存和文件秒速表。
3.进程之间具有独立性,互不干扰,一个进程崩溃,并不会影响到其他进程的运行;线程是独立执行流,一个线程崩溃,可能影响其他的线程运行,从而会使整个进程崩溃。

1.3 线程调度

与多进程的运行方式相同,多线程也是采取并行或并发的方式来执行的。

并行:同一时刻,多个事件同时发生。
并发:同一时间段,多个事件发生(在计算机中,由于CPU运行速度非常快,多个事件看起来就像同时发生)。

所以通常用并发执行来笼统介绍线程或者进程的运行方式。
调度方式

线程的调度,取决于支持的是内核级线程还是用户级线程:
1.对于用户级线程,内核不知道线程的存在,就给了进程很大的自主权。内核只是调度进程,进程中的调度程序选择哪个线程来运行。
2.对于内核级线程,线程的调度就交给了系统完成。

二 线程的创建

2.1 Thread

在Java标准库中,使用了一个类**Thread**来表示线程。所有的线程对象都必须是 Thread 类或其⼦类的实例。
自定义线程类:
1.定义线程子类,并重写Thread类中的run方法,run⽅法的⽅法体就代表了线程需要完成的任务,所以run方法被称为线程执体。

class MyThread extends Thread{
    @Override
    public void run() {
        while (true) {
            System.out.println("哈喽沃尔德");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试类:
1.通过Thread类中的start方法来启动线程start方法会自动调用run方法体

public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
        while (true){
            System.out.println("0.0");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果如下:
在这里插入图片描述
为什么控制台会输出两行文字呢,在我们未接触线程之前,按照我们的设想,start启动后,会在run方法体死循环,不可能执行main方法里面的循环,然而控制台却出现了两行文字并且不断打印,这是因为main方法对应了一个线程,start方法又启动了一个新的线程,每一个线程都是独立执行流,此时两个线程并发(并发或者并行)执行。
图解:
在这里插入图片描述

2.2 多种创建方式

1.自定义类实现Runnable接口,并重写该接⼝的 run() ⽅法,该 run() ⽅法的⽅法体同样是该线程的线程执⾏体,通过Thread构造方法创建。

class MyTread implements Runnable{
     @Override
     public void run() {
         while (true) {
             System.out.println("哈喽沃尔德");
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }
public class ThreadDemo1 {
    public static void main(String[] args) {
        MyTread myTread = new MyTread();
        Thread thread = new Thread(myTread);
        thread.start();
        while (true) {
            System.out.println("0.0");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.匿名内部类
使⽤线程的匿名内部类⽅式,可以⽅便的实现每个线程执⾏不同的线程任务操作。

public class ThreadDemo2 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run(){
                while (true) {
                    System.out.println("哈哈哈哈哈");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
        while (true) {
            System.out.println("嘿嘿嘿");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.Lambda 表达式

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
                while (true){
                    System.out.println("按时发斯蒂芬是的");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        });
        thread.start();
        while (true){
            System.out.println("散货款的那颗");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.3 start()方法和run()方法区别

1.start用来启动线程,启动之后线程进入就绪态,一但运行,就会自动调用run方法,执行run方法里面的包含的内容(某个线程里的run方法即使没执行完毕,也不会影响其它线程的执行,每一个线程都是独立执行流,并发执行),此时run方法属于线程体,run方法执行结束,此时线程结束。

2.run方法如果不通过start自动调用,属于Thread类中的普通方法,在主线程中调用,得run方法的内容执行完毕(顺序执行)才能进行下一步。

总结:start方法启动线程会自动调用run方法,run方法(权限必须为public)只是Thread类中一个普通方法。两者返回值类型都是void。

三 线程基本用法

3.1 线程休眠

调用**sleep()**方法,参数:以毫秒为单位的时间差会抛出InterruptedException异常,需要处理使得线程由运行状态变为阻塞状态,当休眠时间到达时,才会重新变为就绪状态。即使此时系统中没有其他可执行的线程,处于sleep的线程也依然不会执行.

class MyThread extends Thread{
	//重写run方法
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("休眠"+ i + "秒");
			//线程休眠
			//参数:以毫秒为单位
			//需要捕获异常
			try {
				Thread.sleep(1000);  //休眠1秒
			} 
			catch (InterruptedException e) {
				e.printStackTrace();
			}   
		}
	}
}
public class ThreadClass {
	public static void main(String[] args) {
		//实例化一个线程
		MyThread mt=new MyThread();
		mt.start();
	}
    /****线程休眠****/
	
}
//输出形式:每隔1秒输出一个i值

3.2 线程中断

Java中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理(由程序员决定线程如何响应中断。被中断的线程拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择不停止。
中断机制是使用一个称为中断状态的内部标志来实现的。通过Thread.currentThread().isInterrupted()来查看当前标志位状态(默认为false),调用 Thread.interrupt() 设置此标志。

public class ThreadDemo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            // currentThread 是获取到当前线程实例.
            // 此处 currentThread 得到的对象就是 t
            // isInterrupted 就是 t 对象里自带的一个标志位.
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        });

        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 把 t 内部的标志位给设置成 true
        t.interrupt();
    }
}

按理来说,程序应该在三秒钟之后结束运行,而此时却抛出来了异常,并且继续往下执行。这是因为线程 sleep 期间能感受到中断标志,处于休眠中的线程被中断,线程是可以感受到中断信号的,并且会抛出一个InterruptedException 异常,同时清除中断信号,将中断标记位设置成 false。此时while循环再次为真,再次循环。
在这里插入图片描述
解决方法:
在抛出异常后设置break中断,代码如下:

  try {
          Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                  try {
                      Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    break;
                }

3.3 程序等待

1.若在其他线程中执行某个线程join的,在该过程中,其他线程阻塞,待此线程执行完毕,再执行其他线程。
2.使用join会抛出InterruptedException异常,需要处理。
如以下代码:

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            System.out.println("0号线程");
        });
        Thread thread1 = new Thread(()->{
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("1号线程");
        });
        thread.start();
        thread1.start();
 }

在1号线程中使用0号线程thread.join(),1号线程需要等待0号线程结束才能运行。

3.4 获取当前线程引用

通过Thread类中的方法currentThread()来获取当前线程引用。

public class ThreadDemo {
  public static void main(String[] args) {
    Thread thread = Thread.currentThread();
    System.out.println(thread.getName());
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值