javaSE21/10/6

多线程

线程状态

守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕,如后台记录操作日志,监控内存,垃圾回收等待
  • thread.setDaemon(true) 设置守护线程

线程同步

并发:同一个对象被多个线程同时操作

队列和锁

线程不安全案例

  • 买票不安全
//线程不安全,出现0和负数
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket b = new BuyTicket();
        new Thread(b,"我们").start();
        new Thread(b,"你们").start();
        new Thread(b,"黄牛").start();
    }


}
class BuyTicket implements Runnable{
    private int ticketNums = 10;
    boolean flag = true;
    @Override
    public void run() {
        //买票
        while (flag){
            buy();
        }
    }
    public void buy(){
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            System.out.println("您手慢了,票卖完了");
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到第"+ticketNums--+"张票");

    }
}
  • 取钱不安全
public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(2000);
        Drawing drawing = new Drawing(account,2000,"李华");
        Drawing drawing1 = new Drawing(account,2000,"李华妈妈");
        drawing.start();
        drawing1.start();
    }
}
class Account{
    int money;//余额
    public Account(int money) {
        this.money = money;
    }
}
class Drawing extends Thread{
    Account account;//实例化一个账户
    int drawMoney;//取了多少钱
    public Drawing(Account account,int drawMoney,String name){
        super(name);//父类的名,即Thread的名
        this.account=account;
        this.drawMoney=drawMoney;
    }
    //取钱
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (account.money<drawMoney){
            System.out.println(Thread.currentThread().getName()+"您的余额不足!");
            return;
        }
        account.money=account.money-drawMoney;
        System.out.println(Thread.currentThread().getName()+"您取了"+drawMoney);
        System.out.println(Thread.currentThread().getName()+",您的账户余额为"+account.money);
    }
}

线程同步

  • synchronized关键字,分为同步方法和同步块
  • synchronize方法控制对“对象”的访问,每个对象对应一把锁,该方法必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,知道该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
  • 锁的对象是变化的量,需要增删改的对象,同步方法锁的是类本身,同步块锁的是任何对象
  • 解决买票不安全的问题
public synchronized void buy(){
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            System.out.println("您手慢了,票卖完了");
            return;
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到第"+ticketNums--+"张票");

    }
  • 解决银行取钱不安全的问题
public void run() {
        synchronized(account){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (account.money<drawMoney){
                System.out.println(Thread.currentThread().getName()+"您的余额不足!");
                return;
            }
            account.money=account.money-drawMoney;
            System.out.println(Thread.currentThread().getName()+"您取了"+drawMoney);
            System.out.println(Thread.currentThread().getName()+",您的账户余额为"+account.money);
        }

    }
posted @ 2021-10-06 20:47  想吃坚果  阅读(76)  评论(0)    收藏  举报