线程的休眠、状态和安全问题

一.线程休眠

休眠线程有两种实现:
a.使⽤ sleep 休眠
b.使⽤ TimeUnit 休眠

1.1 sleep 休眠

在这里插入图片描述

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(60*1000);
            } catch (InterruptedException e) {
                System.out.println("我接收到了终止执行通知");
//                e.printStackTrace();
            }
        });
        thread.start();


        Thread.sleep(1000);
        System.out.println("终止子线程 thread");
        thread.interrupt();

在这里插入图片描述

1.2TimeUnit 休眠

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

public class ThreadTimeUtil {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程开始执行了:"+ LocalDateTime.now());
        TimeUnit.DAYS.sleep(1);//休眠一天
        TimeUnit.HOURS.sleep(1);//⼩时
        TimeUnit.MINUTES.sleep(1);//分
        TimeUnit.SECONDS.sleep(1);//秒
        TimeUnit.MILLISECONDS.sleep(1000);//毫秒
        TimeUnit.MICROSECONDS.sleep(1000);//微妙
        TimeUnit.NANOSECONDS.sleep(1000);//纳秒

    }
}

二.线程状态

1.1打印所有线程状态

public static void main(String[] args) {
        printState();//打印所有线程状态
    }

    private static void printState() {
        for (Thread.State item : Thread.State.values()) {
            System.out.println(item);
        }
    }

在这里插入图片描述

a.NEW: 新建状态,安排了工作还未开始行动。
b.RUNNABLE:运行状态,分为①RUNNABLE:得到时间片运行中的状态 ②Ready:未得到时 间片的就绪状态
c.BOLCKED:阻塞状态,当遇到锁时,会出现这种状态。
d.WAITING:无限期的等待状态 。
e.TIMED_WAITING:有明确结束时间的等待状态。
f.TERMINATED:终止状态,当线程任务结束之后会变成此状态。

在这里插入图片描述

1.2线程状态转变

在这里插入图片描述

public static void main(String[] args) throws InterruptedException {
//        printState();//打印所有线程状态
        Thread t1 = new Thread(() -> {
            System.out.println("当前线程状态2:"+Thread.currentThread().getState());
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("当前线程状态:" + t1.getState());
        t1.start();

        //让主线程休眠1s
        Thread.sleep(1000);
        System.out.println("当前线程的状态3:" + t1.getState());

        //等待子线程执行完
        t1.join();
        System.out.println("当前线程的状态4:" + t1.getState());

    }

    /**
     * 打印所有线程状态
     */
    private static void printState() {
        for (Thread.State item : Thread.State.values()) {
            System.out.println(item);
        }
    }

在这里插入图片描述

二.线程安全问题

2.1相关概念

概念:线程不安全指的是程序在多线程的执⾏结果不符合预期。
单线程:

static class Counter{
          private int num=0;
          private  int MAX_COUNT=0;
          public Counter(int MAX_COUNT){
               this.MAX_COUNT=MAX_COUNT;
          }
          //++方法
          public void increment(){
               for (int i = 0; i < MAX_COUNT; i++) {
                    num++;
               }
          }
          //--方法
          public void  decrement(){
               int temp=0;
               for (int i = 0; i < MAX_COUNT; i++) {
                    num--;
               }
          }
          public  int getNum(){
               return num;
          }
     }
 
 
     public static void main(String[] args) throws InterruptedException {
          Counter counter=new Counter(100000);
          counter.increment();
          counter.decrement();
          System.out.println("最终结果:"+counter.getNum());
     }

在这里插入图片描述
多线程:

static class Counter{
          private int num=0;
          private  int MAX_COUNT=0;
          public Counter(int MAX_COUNT){
               this.MAX_COUNT=MAX_COUNT;
          }
          //++方法
          public void increment(){
               for (int i = 0; i < MAX_COUNT; i++) {
                    num++;
               }
          }
          //--方法
          public void  decrement(){
               int temp=0;
               for (int i = 0; i < MAX_COUNT; i++) {
                    num--;
               }
          }
          public  int getNum(){
               return num;
          }
     }
 
 
     public static void main(String[] args) throws InterruptedException {
          Counter counter=new Counter(100000);
          Thread  thread1=new Thread(()->{
               counter.increment();
          });
          Thread thread2=new Thread(()->{
               counter.decrement();
          });
          thread1.start();
          thread2.start();
          thread1.join();
          thread2.join();
          System.out.println("最终结果:"+counter.getNum());
     }

在这里插入图片描述
此时,多线程结果是不确定的。

2.2线程不安全原因

2.2.1抢占式执行

CPU资源有限,多个线程争抢着执行任务,就会导致线程不安全问题。

2.2.2 多个线程修改同⼀个变量

因为两个线程都是修改 num这个变量,线程在并发执行的时候会出现不安全的问题,但如果各自修改各自的变量,就不会出现这个问题。

 static class Counter{
//          private int num=0;
          private int num1=0;
          private int num2=0;
          private  int MAX_COUNT=0;
          public Counter(int MAX_COUNT){
               this.MAX_COUNT=MAX_COUNT;
          }
          //++方法
          public int increment(){
               for (int i = 0; i < MAX_COUNT; i++) {
                    num1++;
               }
               return num1;
          }
          //--方法
          public int decrement(){
               int temp=0;
               for (int i = 0; i < MAX_COUNT; i++) {
                    num2--;
               }
               return num2;
          }
          public  int getNum(){
               return num1+num2;
          }
     }
 
 
     public static void main(String[] args) throws InterruptedException {
          Counter counter=new Counter(100000);
          Thread  thread1=new Thread(()->{
               counter.increment();
          });
          Thread thread2=new Thread(()->{
               counter.decrement();
          });
          thread1.start();
          thread1.join();
          thread2.start();
          thread2.join();
          System.out.println("最终结果:"+counter.getNum());
     }

2.2.3非原子性操作

什么是原子性?
一段程序必须一次性执行完,中间不能停顿。

不保证原⼦性会给多线程带来什么问题?
如果⼀个线程正在对⼀个变量操作,中途其他线程插⼊进来了,如果这个操作被打断了,结果就可能是错误的。

2.2.4内存可见性

可⻅性指, ⼀个线程对共享变量值的修改,能够及时地被其他线程看到.

Java 内存模型 (JMM): Java虚拟机规范中定义了Java内存模型.
⽬的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到⼀致的并发效果.
在这里插入图片描述
a.
当线程要读取⼀个共享变量的时候, 会先把变量从主内存拷⻉到⼯作内存, 再从⼯作内存读取数据.
b.
当线程要修改⼀个共享变量的时候, 也会先修改⼯作内存中的副本, 再同步回主内存.

2.2.5指令重排序

编译器优化的本质是调整代码的执⾏顺序,在单线程下没问题,但在多线程下容易出现混乱,从⽽造成线程安全问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值