多线程(一)线程基础、线程之间的共享和协作

本文介绍了多线程的基础概念,包括CPU时间片轮转、进程与线程的区别,以及并行与并发的区别。接着,详细讲解了Java中线程的创建方式,特别是如何安全地停止线程,包括过时与推荐的方法,并通过代码示例展示了如何处理InterruptedException。此外,文章还探讨了线程间的状态转换,线程同步机制如synchronized、volatile关键字以及ThreadLocal的使用。
摘要由CSDN通过智能技术生成

1.基础概念

CPU核心数和线程数的关系
核心数:线程数=1:1 ;使用了超线程技术后—> 1:2

CPU时间片轮转机制
又称RR调度,会导致上下文切换

什么是进程和线程
进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源
线程:CPU调度的最小单位,必须依赖进程而存在。(先有进程再有线程。CPU先将资源分配给进程,然后线程再使用资源)

澄清并行和并发
并行:同一时刻,可以同时处理事情的能力
并发:与单位时间相关,在单位时间内可以处理事情的能力

高并发编程的意义、好处和注意事项
好处:充分利用cpu的资源、加快用户响应的时间,程序模块化,异步化
问题:
线程共享资源,存在冲突;
容易导致死锁;
启用太多的线程,就有搞垮机器的可能

2.认识Java里的线程

2.1 创建线程的三种方式

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口
    Runnable和Callable的区别: Runnable接口中的run方法没有返回值,而Callable接口中的call方法有返回值
public class MyThread extends Thread {
   

    //实现Runnable接口
    private static class UseRun implements Runnable{
   

        @Override
        public void run() {
   
            System.out.println("I'm runnable implements");
        }
    }

    //实现Callable接口
    private static class UseCall implements Callable<String>{
   

        @Override
        public String call() throws Exception {
   
            System.out.println("I'm callable implements");
            return "callable";
        }
    }

    //测试
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        UseRun useRun = new UseRun();
        //实现Runnable接口的类 需要交给线程类Thread去执行
        new Thread(userRun).start();

       UseCall useCall = new UseCall();
       //PS:实现Callable的类无法直接转化为Thread 这就要使用FutureTask类 该类继承了Runnable接口
        //相当于将UseCall -> Runnable -> Thread
        FutureTask<String> futureTask = new FutureTask<>(userCall);
        //执行该线程
        new Thread(futureTask).start();
        //获取并且打印UserCall的返回值
        System.out.println(futureTask.get());
    }

}

2.2 如何让Java里的线程安全停止工作

①线程自然终止:②自然执行完或抛出未处理异常

2.2.1 已经过时的三种方法:stop(),resume(),suspend()
  • stop() :过于强硬会导致线程不会正确释放资源,
  • suspend() (挂起) :处于挂起状态,线程不会释放资源 当其他的线程需要资源时 会导致资源无法获取 这样就容易导致死锁。
2.2.2 现在推荐使用的三种方法
  • interrupt: 调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
  • isInterrupted() 判定当前线程是否处于中断状态(即判断线程标志位是否为true)。
  • static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。
    方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
  • interrupted()方法是静态的,底层调用了isInterrupted()方法,并且会将中断标志位重置。
public static boolean interrupted() {
   
    return currentThread().isInterrupted(true);
}

这三种方法只有Thread以及其子类才能够使用

2.2.3 代码演示

1.继承Thread类创建线程方式 安全中断线程的代码:

public class EndThread {
   

    private static class UseThread extends Thread{
   

        public  UseThread(String name){
   
            super(name);
        }

        //重写Thread中的run方法
        @Override
        public void run(){
   
            String name = Thread.currentThread().getName();
            //判断当前的线程是否被中断
            while(! isInterrupted()){
   
                //获取当前运行线程的名字
                System.out.println("Thread:" + name + " is run");
            }
            System.out.println("interrupt flag is : " + isInterrupted());
        }
    }

    public static void main(String[] args) throws InterruptedException {
   
        //创建线程的实例对象
        Thread endThread = new UseThread("endThread");
        endThread.start();
        //令主线程休眠2秒 这样就不会立刻执行后面的interrupt()方法
        Thread.sleep(2000);
        endThread.interrupt();
    }
}

UseThread线程会运行2s 直到2s后main方法执行endThread.interrupt(); 线程中断。

执行结果:

Thread:endThread is run
Thread:endThread is run
Thread:endThread is run
Thread:endThread is run
Thread:endThread is run
Thread:endThread is run
interrupt flag is : true
  • 如果将run方法中的代码改为如下:
 @Override
        public void run(){
   
            String name = Thread.currentThread().getName();
            //判断当前的线程是否被中断
            while(true){
   
                //获取当前运行线程的名字
                System.out.println("Thread:" + name + " is run");
                System.out.println("interrupt flag is : " + isInterrupted());
            }
        }

执行结果为:

Thread:endThread is run
interrupt flag is : false
Thread:endThread is run
interrupt flag is : false
Thread:endThread is run
interrupt flag is : false

interrupt flag is : true
Thread:endThread is run
interrupt flag is : true
Thread:endThread is run
interrupt flag is : true
Thread:endThread is run

程序会永远执行下去。 可以看到2s之前中断标志一直为false,2s后运行到主方法的endThread.interrupt();后中断标志变为true 但程序仍然会一直运行,这恰恰说明了 java的线程是协作式的并不是抢占式的。即使发出了中断线程的信号,线程仍然执行,因为线程是否中断最终的决定权是在线程本身。

2.实现Runnable接口方式创建线程 安全中断线程的方法

其实该方法和上面的方法大同小异 只是不能直接使用interrupt()、isInterrupted()、interrupted()这三种方法

public class EndRunnable {
   

    private static class UseRunnable implements Runnable{
   

        @Override
        public void run() {
   
            String name = Thread.currentThread().getName();//❤
            //判断当前线程是否被中断 使用Thread.currentThread().isInterrupted() 是因为只有Thread类才有这个方法
            while (! Thread.currentThread().isInterrupted()){
   //❤
                //获取当前运行线程的名字
                System.out
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值