JUC并发编程-01:线程基础知识和常用方法

JUC开发基础知识

先有进程,然后进程可以创建线程,线程是依附在进程里面的,线程里面包含多个协程

进程之间不共享全局变量,线程之间共享全局变量(线程通信就是用的这个,线程之间可以共享全局资源)

进程、线程、协程

进程就是一个应用单元、一个进程由多个线程组成。线程是CPU调度的基本单位。协程由java19新出也就是虚拟线程。
在这里插入图片描述

  • 并行、并发、串行
    并发:CPU上下文切换交替执行 并行:多核CPU同时执行任务

CPU核心数和线程数的关系

在这里插入图片描述

上下文切换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

start和run

start方法会启动一个线程,程序会异步执行。而执行run方法不会启动一个线程,代码还是同步执行。

sleeep

线程睡眠方法。在以后的代码中推荐使用:TimeUnit.SECONDS.sleep(1);
在这里插入图片描述

在where(true)循环访问锁的过程中,可以加入sleep让线程阻塞时间,防止大量占用CPU资源。

让步和优先级

Thread.yield(),方法的作用:暂停当前正在执行的线程对象,并执行其他线程。

  • yield()做的是让当前运行的线程回到可运行状态,以允许具相同优先级的其他线程获得运行机会。因此使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield达到让步目的。

yield()方法并不能保证线程一定会让出CPU资源,它只是一个提示,告诉线程调度器当前线程愿意让出CPU资源。具体是否让出CPU资源,还是由调度器决定。(如果CPU资源不紧张,一般也不会让出,如果CPU资源紧张,调度器收到让步通知后,会将占有资源优先分给其他同优先级线程)

public class Test {
    public static void main(String[] args) {
        Runnable task1=new Task1();
        Runnable task2 =new Task2();

        Thread t1=new Thread(task1);
        Thread t2=new Thread(task2);

        t1.start();
        t2.start();
    }

   static class Task1 implements Runnable{

        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("A:"+i);
            }
        }
    }

   static class Task2 implements Runnable{

        public void run() {
            for (int i = 0; i < 6; i++) {
                Thread.yield();
                System.out.println("B:"+i);
            }
        }
    }
}

优先级

t1.setPriority(Thread.MAX_PRIORITY);,设置线程执行优先级,数字越大优先级越高和yield一样,也是通知线程调度器,如果CPU资源空闲一般会优先执行,如果CPU资源紧张,如果没有其他线程让出资源的情况下也只能干等着。

public class Test {
    public static void main(String[] args) {
        Runnable task1=new Task1();
        Runnable task2 =new Task2();

        Thread t1=new Thread(task1);
        t1.setPriority(Thread.MAX_PRIORITY);
        Thread t2=new Thread(task2);

        t1.start();
        t2.start();
    }

   static class Task1 implements Runnable{

        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("A:"+i);
            }
        }
    }

   static class Task2 implements Runnable{

        public void run() {
            for (int i = 0; i < 6; i++) {
                Thread.yield();
                System.out.println("B:"+i);
            }
        }
    }
}

打断线程

正在睡眠的线程被打断,会报java.lang.InterruptedException异常

public class Sleep {
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("睡眠结束");
        });

        t1.start();
        t1.interrupt();
    }
}
  • 打断线程
    在这里插入图片描述静态方式会清除打断标记,此时如果中断正在执行的线程,则撤销打断代码不会报异常。对象方法不会清除打断标记,撤销打断,还是会报异常

撤销打断

public class Sleep {
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            try {
                Thread.interrupted();
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("睡眠结束");
        });

        t1.start();
        t1.interrupt();
    }
}
  • 对象方法不会撤销打断,清除打断标志
@Slf4j
public class Sleep {
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("睡眠结束");
        });

        t1.start();
        log.info(t1.isInterrupted()+"");
        t1.interrupt();
        log.info(t1.isInterrupted()+"");
    }
}

线程中断

interrupt()方式会中断线程。仅仅是设置线程的中断状态为ture,不会停止线程。在这里插入图片描述

  • 代码证明
public class Sleep {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true){
                System.out.println("定时监控");
            }
        });

        t.start();
        t.interrupt(); //线程中断
        System.out.println(t.isInterrupted());
    }
}

线程手动中断

如果当前线程中断标记是true,则手动中断当前线程

public class Sleep {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true){
                System.out.println("定时监控");

                //获取线程中断标记
                boolean interrupted = Thread.interrupted();
                //如何线程中断标记是true,则中断该线程
                if (interrupted){
                    break;
                }
            }
        });

        t.start();
        t.interrupt();
        System.out.println(t.isInterrupted());
    }
}
  • 需要特别注意和sleep配合使用的时候容易出现的问题
    当出现InterruptedException 会清除中断标记 设置成false,此时再手动中断线程是无法中断的
public class Sleep {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true){

                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    //当出现InterruptedException 会清除中断标记  设置成false,此时再手动中断线程是无法中断的
                    e.printStackTrace();
                }
                System.out.println("定时监控");

                if (Thread.interrupted()) { //false
                    break;
                }
            }
        });

        t.start();
        t.interrupt();
        System.out.println(t.isInterrupted());
    }
}

解决方法:再次加上中断

public class Sleep {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            while (true){

                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    //当出现InterruptedException 会清除中断标记  设置成false,此时再使用静态方法手动中断线程是无法中断的
                    e.printStackTrace();
                    
                    //再次加上中断标记
                    Thread.currentThread().interrupt();
                }
                System.out.println("定时监控");

                if (Thread.interrupted()) {
                    break;
                }
            }
        });

        t.start();
        t.interrupt();
        System.out.println(t.isInterrupted());
    }
}

加入线程join()

作用:子线程执行完毕后,主线程才执行。比如t.join()后,t线程执行完毕,主线程才执行

public class Sleep {

    static int value=1;
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            value=10;
            System.out.println("线程runable");
        });

        t.start();

        try {
            //加入线程,t线程执行完毕才执行主线程,也就是t线程先执行并执行完毕后才执行主线程
            t.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("主线程:"+value);
    }
}

isAlive

线程是否存活

public class Sleep {

    static int value=1;
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            value=10;
            System.out.println("线程runable");
        });

        t.start();
        System.out.println(t.isAlive()); //true
        t.join();
        System.out.println(t.isAlive()); //false,由于加入线程了,子线程已经执行完毕,此时线程不是存活状态,false
        System.out.println("主线程:"+value);
    }
}

守护线程

守护线程会伴随所有普通线程,所有普通线程结束后,守护线程立马终结
在这里插入图片描述
在这里插入图片描述

public class Sleep {

    static int value=1;
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("子线程:"+i);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.setDaemon(true); //设置t为守护线程
        t.start();
        System.out.println("主线程:"+value);
    }
}

实现Callable实现线程

声明一个任务

public class ExcuteSumTask implements Callable<Integer> {

    int t=100;

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 1; i <= t; i++) {
            sum=sum+i;
        }
        return sum;
    }
}
  • 测试
    声明一个未来任务对象,将定义的任务放到任务对象中
public class Test {
    public static void main(String[] args) {
        Callable<Integer> excuteTask=new ExcuteSumTask();
        
        //定义一个未来任务对象
        FutureTask<Integer> task = new FutureTask<>(excuteTask);
        Thread t=new Thread(task);

        //启动线程
        t.start();
        try {
            //获得线程执行结果
            System.out.println(task.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值