线程状态+线程不安全案例

线程的五种状态

参考JDK帮助文档:
在这里插入图片描述

本图片摘自bilibili UP:狂神说Java注:此图片摘自bilibili UP:狂神说Java

  • 创建状态:Thread t = new Thread();
    new一个线程,则此线程进入创建状态
  • 就绪状态:调用start()方法,线程进入就绪状态,但不会被立即执行
  • 执行状态:当线程被CPU调度时,线程进入运行状态
  • 阻塞状态:sleep()、wait()或者同步锁等方法,使得线程进入阻塞状态。阻塞解除,线程进入就绪状态,等待CPU调度
  • 死亡状态:线程中断(非自然死亡)或者结束(自然死亡),就进入死亡状态,无法再次启动。

线程的停止

不推荐使用JDK提供的stop()、destroy()等方法
定义标志位
使用自定义的stop 方法,改变标志位,来控制线程停止
具体实现:

package com.Thread.demo03;

public class TestStop implements Runnable{
    private boolean flag=true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run......Thread"+i++);
        }
    }
    //自己定义一个stop方法,使得标志位改变,来终止线程
    public void stop(){
        flag=false;
    }

    public static void main(String[] args) {
//        new一个runnable接口的实现类的对象
        TestStop testStop = new TestStop();
//        new一个线程,然后丢入创建的接口实现类的对象,然后启动线程——>就绪状态,不会立刻执行,需要等待CPU调度
        new Thread(testStop).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if (i==520){
                testStop.stop();
                System.out.println("线程停止");
            }
        }
    }
}

线程休眠

  • sleep(时间)指定当前线程堵塞的毫秒数
  • sleep存在异常InterruptedException;,需要抛出
  • 时间达到之后进入就绪状态
  • slee可以模拟网络延时和倒计时等等
  • 每个对象都有自己的锁,sleep不会释放锁

实例:获取当前系统时间,休眠一秒

public static void main(String[] args) throws InterruptedException {
        Date startime = new Date(System.currentTimeMillis());//获取当前时间
        while (true){
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startime));
            startime = new Date(System.currentTimeMillis());//更新当前时间
        }

    }

线程礼让

礼让不一定成功,因为CPU调度是随机的

package com.Thread.demo03;

public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }

}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束");
    }
}

执行结果:
在这里插入图片描述在这里插入图片描述

线程强制执行

join ()——插队,其他线程阻塞,少用

package com.Thread.demo03;
//插队,其他线程阻塞
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("VIP氪金玩家"+i+"已进入游戏");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        for (int i = 0; i < 500; i++) {
            if (i==100){
                thread.join();
            }
            System.out.println("main"+i);
        }
    }
}

线程状态观测

Thread.State state = thread.getState();
        System.out.println(state);

线程不安全案例

1.不安全的购票

创建一个类实现Runnable接口
重写run()
定义buy()方法,具体定义如何买票:
设置标志位,控制线程终止
每次进入判断票数是否为0,当票数为0的时候,标志位变为false
利用sleep()方法,使得线程阻塞,增加错误的发生性
输出每次抢票结果

package com.Thread.state;

public class UnsaftyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        new Thread(station,"DJ").start();
        new Thread(station,"AI").start();
        new Thread(station,"黄牛").start();
        
    }

}

class BuyTicket implements Runnable{
    private int ticketNum=10;
    private boolean flag=true;
    @Override
    public void run() {
        while (flag) {
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private void buy() throws InterruptedException {
        if (ticketNum==0){
            flag=false;
            return;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName()+"抢到了第"+ticketNum--);
    }
}

2.不安全的银行账户

情境:两人同时操作一个账户
因为线程会把账户余额信息,copy到自己的内存中,故此二者看到的账户余额是相同的,而二者都可以对账户进行操作,造成线程不安全

package com.Thread.state;

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");
        Drawing you =new Drawing(account,50,"你");
        Drawing wife =new Drawing(account,100,"你老婆");

        you.start();
        wife.start();
    }
}
/*1.首先定义一个账户
里面存储账户的钱数和账户名称
定义有参构造方法
 */
class Account{
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
/*
2.定义一个取钱方法继承Thread
属性包括:取走钱数、卡内余额,本人现有金额
定义有参构造方法
实现run方法
    判断所剩余额是否够取
    给取走钱数和卡内余额赋值

 */
class Drawing extends Thread{
    Account account;
    double drawMoney;
    double nowMoney;

    public Drawing(Account account,double drawMoney , String name){
        super(name);
        this.account=account;
        this.drawMoney=drawMoney;

    }

    @Override
    public void run() {
        //如果银行存款-取款<0  说明账户内余额不足
        if (account.money-drawMoney<0){
            System.out.println("尊敬的客户:"+Thread.currentThread().getName()+",你的账户余额不足");
            return;
        }

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

        //余额=余额-取走的钱
        account.money-=drawMoney;
        //本人现有金额=原有金额+从银行取走的钱
        nowMoney=nowMoney+drawMoney;
        //Thread.currentThread().getName()
        System.out.println(account.name+"余额为:"+account.money);
        //Thread.currentThread().getName()=this.getName()
        System.out.println(this.getName()+"手里的钱::"+nowMoney);

    }
}

3.不安全列表

  • 两个线程都往一个位置添加数据,这样的话,后者会把前者已经添加的数据覆盖,导致线程不安全
package com.Thread.state;

import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list=new ArrayList<String>(){};
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(2000);
        System.out.println(list.size());
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值