java多线程银行排队所取号码丢失

我在编写多线程银行排队代码时,使用栈来赋值所取号码,但是出现了部分号码缺失的情况,应该如何解决?
代码如下:


import java.io.File;
import java.io.IOException;
import java.util.*;
class Stack{
    int size=1000;
    int []data;
    int top=-1;

    public Stack(){
        this.data=new int[size];
        for(int i=1000;i>0;i--){
            this.top++;
            this.data[this.top]=i;
        }
    }
    public int pop(){
        int item=this.data[this.top];
        this.top--;
        return item;
    }
}
class Custom{
    private final String account;
    private final String ctype;//所需服务
    private double inout;
    public Custom(String account,String ctype){
        this.account=account;
        this.ctype=ctype;
    }
    public Custom(String account,String type,double inout){
        this.account=account;
        this.ctype=type;
        this.inout=inout;

    }
    public String getAccount() {
        return account;
    }
    public String getCtype() {
        return ctype;
    }
    public double getInout() {
        return inout;
    }
}
class ATM implements Runnable{
    private double []surplus=new double[200];//余额
    private int visa;
    Map<String,Double> m=new HashMap<>();
    String type;
    public ATM(String type){
        this.type=type;
    }
    public void fget(){//从文件读取数据
        int i=0;
        try {
            Scanner sc=new Scanner(new File("余额.txt"));
            while (sc.hasNextLine()){
                surplus[i]=Double.parseDouble(sc.nextLine());
                i++;
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public void link(){//建立键值对
        int i=0;
        int temp=100;
        for(;i<200;i++)
        {
            m.put(String.valueOf(temp),surplus[i]);
            temp++;
        }
    }
    public boolean classify(String account){//是否为跨行
        char firstCh=account.charAt(0);
        return firstCh == '1';
    }
    public void serve(String account,double inout,boolean same,int x){//修改余额
        double temp;
        double commission=2.0;//手续费
        if(same){
            temp=m.get(account)+inout;
            m.put(account,temp);
            System.out.println(x+"号 "+account+"***"+" 余额变更"+inout+"元 手续费:0元");
        }
        else {
            temp=m.get(account)+inout-commission;
            m.put(account,temp);
            System.out.println(x+"号 "+account+"***"+" 余额变更"+inout+"元 手续费:"+commission+"元");
        }
    }
    public void serve(String account,int x,String type){//服务机
        System.out.println(x+"号 "+account+"***"+" 选择了"+type);
    }
    static Stack s=new Stack();
    public void run(){
        String []select={"g","p","s"};
        int x=1;
        while (x<20){
            x=s.pop();
            synchronized (this){
                int num=(int)(100+Math.random()*199);
                int temp=(int)(Math.random()*3);//随机选择服务
                String account=String.valueOf(num);//随机账户
                double inout=Math.random()*100-50;
                String middle=String.format("%.2f",inout);//转为两位小数
                Custom c;
                fget();
                link();
                inout=Double.parseDouble(middle);
                if(inout>=0&&temp!=2){
                    temp=1;
                }
                else if(temp!=2){
                    temp=0;
                }
                if(classify(account)){
                    if(inout>m.get(account)){
                        System.out.println("账户余额不足");
                    }
                }
                else {
                    if(inout>(m.get(account)-2)){
                        System.out.println("账户余额不足");
                    }
                }

                if(select[temp].equals("s")){
                    c=new Custom(account,select[temp]);
                }
                else {
                    c=new Custom(account,select[temp],inout);
                }

                if(type.equals("服务机")&&c.getCtype().equals("s"))
                {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    serve(c.getAccount(),x,type);
                }
                else if((!c.getAccount().equals("s"))&&type.equals("存取款机")){
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else if (c.getCtype().equals("p")&&type.equals("存款机")) {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else if (c.getCtype().equals("g")&&type.equals("取款机")) {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else {
                    continue;
                }
                try {
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(type+"办理业务已完成");
            }
            }

    }
}
public class TestATM {
    public static void main(String []args){
        ATM atm1=new ATM("服务机");
        Thread t1=new Thread(atm1);
        t1.start();
        ATM atm2=new ATM("存取款机");
        Thread t2=new Thread(atm2);
        t2.start();
        ATM atm3=new ATM("取款机");
        Thread t3=new Thread(atm3);
        t3.start();
        ATM atm4=new ATM("存款机");
        Thread t4=new Thread(atm4);
        t4.start();
    }
}

部分结果:

img

jiyugtt
提供的代码中,出现了多线程环境下的问题,导致部分号码丢失。问题出在以下代码块:

static Stack s = new Stack();

这里的 Stack 是你自己实现的栈数据结构,并且使用了 static 修饰,这意味着所有的线程共享同一个栈对象。在多线程环境下,多个线程同时操作栈,会导致数据竞争和不确定的结果。

解决该问题的方法是使用线程安全的数据结构来存储号码,以避免数据竞争。可以考虑使用 java.util.concurrent 包下的 ConcurrentLinkedQueue 或 BlockingQueue 来存储号码。这些数据结构是线程安全的,可以在多线程环境下安全地进行入队和出队操作。

下面是修改后的代码示例,使用 ConcurrentLinkedQueue 来存储号码:


import java.util.concurrent.ConcurrentLinkedQueue;

class CustomQueue {
    private static ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();

    public static void initQueue() {
        for (int i = 1000; i > 0; i--) {
            queue.add(i);
        }
    }

    public static int pop() {
        return queue.poll();
    }
}

class ATM implements Runnable {
    // ...

    public void run() {
        // ...

        int x = 1;
        while (x < 20) {
            x = CustomQueue.pop();
            synchronized (this) {
                // ...
            }
        }
    }
}

public class TestATM {
    public static void main(String[] args) {
        CustomQueue.initQueue();

        // ...
    }
}

在修改后的代码中,使用 ConcurrentLinkedQueue 作为号码队列,并在程序启动时调用 CustomQueue.initQueue() 初始化队列。每个线程通过调用 CustomQueue.pop() 方法来获取号码,保证了多线程环境下的安全性。

通过这种方式,你应该能够避免部分号码丢失的问题,并且在多线程环境下正常地进行银行排队取号码的操作

多线程情况下 static Stack s=new Stack(); 这一句可能出现多个对象,这种情况会导致线程不安全。
可以使用加锁,单例等形式来做,
例如做一个单例方法,获取对象直接 Stack.instance();

修改了Stack 和 ATM两个类,修改的地方都有注释。


/**
 * 修改为单例模式。
 */
public class Stack {
    int size=1000;
    int []data;
    int top=-1;
    private static Stack instance = new Stack();
    private Stack(){
        this.data=new int[size];
        for(int i=1000;i>0;i--){
            this.top++;
            this.data[this.top]=i;
        }
    }
    public static Stack getInstance(){
        return instance;
    }

    public synchronized int pop(){
        int item=this.data[this.top];
        this.top--;
        return item;
    }
}


import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

class ATM implements Runnable{
    private double []surplus=new double[200];//余额
    private int visa;
    Map<String,Double> m=new HashMap<>();
    String type;
    public ATM(String type){
        this.type=type;
    }
    public void fget(){//从文件读取数据
        int i=0;
        try {
            Scanner sc=new Scanner(new File("余额.txt"));
            while (sc.hasNextLine()){
                surplus[i]=Double.parseDouble(sc.nextLine());
                i++;
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public void link(){//建立键值对
        int i=0;
        int temp=100;
        for(;i<200;i++)
        {
            m.put(String.valueOf(temp),surplus[i]);
            temp++;
        }
    }
    public boolean classify(String account){//是否为跨行
        char firstCh=account.charAt(0);
        return firstCh == '1';
    }
    public void serve(String account,double inout,boolean same,int x){//修改余额
        double temp;
        double commission=2.0;//手续费
        if(same){
            temp=m.get(account)+inout;
            m.put(account,temp);
            System.out.println(x+"号 "+account+"***"+" 余额变更"+inout+"元 手续费:0元");
        }
        else {
            temp=m.get(account)+inout-commission;
            m.put(account,temp);
            System.out.println(x+"号 "+account+"***"+" 余额变更"+inout+"元 手续费:"+commission+"元");
        }
    }
    public void serve(String account,int x,String type){//服务机
        System.out.println(x+"号 "+account+"***"+" 选择了"+type);
    }
    //这里修改了Stack的创建方式。
    Stack s= Stack.getInstance();
    public void run(){
        String []select={"g","p","s"};
        int x=1;
        while (x<20){
            x=s.pop();
            synchronized (this){
                int num=(int)(100+Math.random()*199);
                int temp=(int)(Math.random()*3);//随机选择服务
                String account=String.valueOf(num);//随机账户
                double inout=Math.random()*100-50;
                String middle=String.format("%.2f",inout);//转为两位小数
                Custom c;
                fget();
                link();
                inout=Double.parseDouble(middle);
                if(inout>=0&&temp!=2){
                    temp=1;
                }
                else if(temp!=2){
                    temp=0;
                }
                if(classify(account)){
                    if(inout>m.get(account)){
                        System.out.println("账户余额不足");
                    }
                }
                else {
                    if(inout>(m.get(account)-2)){
                        System.out.println("账户余额不足");
                    }
                }

                if(select[temp].equals("s")){
                    c=new Custom(account,select[temp]);
                }
                else {
                    c=new Custom(account,select[temp],inout);
                }

                if(type.equals("服务机")&&c.getCtype().equals("s"))
                {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    serve(c.getAccount(),x,type);
                }
                else if((!c.getAccount().equals("s"))&&type.equals("存取款机")){
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else if (c.getCtype().equals("p")&&type.equals("存款机")) {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else if (c.getCtype().equals("g")&&type.equals("取款机")) {
                    System.out.println(type+"空闲");
                    System.out.println(type+"正在办理"+x+"号"+c.getAccount()+"***"+"的业务");
                    boolean same=classify(c.getAccount());
                    serve(c.getAccount(),c.getInout(),same,x);
                }
                else {
                    //这里补充了一段打印。
                    System.out.println("正在办理"+x+"号"+c.getAccount()+"***"+"的业务,但不匹配,type = " + type + ", c.getCtype() = " + c.getCtype());
                    continue;
                }
                try {
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(type+"办理业务已完成");
            }
        }

    }
}

通过加锁的方式,确保线程安全

试试这个

package 排队;
 
public class Test01 {
    public static void main(String[] args){
        St  st = new St();
        Custm[] cus = new Custm[20];
        int[] ran = {1,1,1,0,1,0,1,1,1,0,1};
        //int[] ran = {1,0,1,1,0,1,0,1,0,1,1};
        for(int i=0;i<20;i++){
            int a = (int)(Math.random()*10);
            cus[i] = new Custm(i+1,ran[a]);
            st.add(cus[i]);
            
        }
        Worke wort = new Worke(st, "vip", true);//vip窗口,线程1
        Thread t1 = new Thread(wort);
        t1.start();
        
        Worke wort1 = new Worke(st, "1号" , false);//普通窗口,线程2,
        Thread t2 = new Thread(wort1);
        t2.start();
        
        Worke wort2 = new Worke(st, "2号" , false);//普通窗口,线程3,
        Thread t3 = new Thread(wort2);
        t3.start();
        Worke wort4 = new Worke(st, "3号" , false);//普通窗口,线程4,
        Thread t4 = new Thread(wort4);
        t4.start();
        
        
    }
}
class Custm{
    int key;
    int num;
    public Custm(int n, int k){
        num=n;
        key=k;
    }
}
 
class base {
    
}
class Worke implements Runnable{
    boolean isvip;
    St s;
    String ThreadName;
    public Worke(St ss,String n ,boolean vip){
        s=ss;
        ThreadName = n;
        isvip = vip;
    }
    boolean asd=true;
    public void run(){
        while(asd){
            if(s.isEmpty()==false){
                
                if(isvip){
            //        synchronized(this){
                        
                    Custm cu = s.dell().cus;
                    if(cu.key==0){
                        
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【vip】顾客准备!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客就绪!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客正在办理!");
                    try {
                        Thread.sleep((int)(Math.random()*500));
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客已离开-------!");
                    
                //    }else{
                        
                //        try {
            //                Thread.sleep((int)(Math.random()*500));
            //            } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
            //                e.printStackTrace();
            //            }
        //            }
                    }
                    
                }else{
            //        synchronized(this){
                        
                    Custm cu = s.dell().cus;
                    if(cu.key==0){
                        
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【vip】顾客准备!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客就绪!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客正在办理!");
                    try {
                        Thread.sleep((int)(Math.random()*500));
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客已离开-------!");
                    }else{
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【普通】顾客准备!");
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客就绪!");
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客正在办理!");
                        try {
                            Thread.sleep((int)(Math.random()*500));
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客已离开-------!");
                        
                    }
            //        }
                    
                }
            }else{
                asd=false;
            }
            
        }
    }
}
class St{
    Node head;
    Node tail;
    public St(){
        tail=head=null;
    }
    public boolean isEmpty(){
        if(head==null){
            return true;
        }
        return false;
    }
    
    public void add(Custm c){
        Node node = new Node(c);
        if(isEmpty()){
            head=tail=node;
            head.front=null;
            tail.next=null;
        }else{
            tail.next=node;
            node.front=tail;
            tail=node;
            tail.next=null;
        }
    }
    public Node dell(){
        if(isEmpty()==false){
            if(head.next==null){
                Node nod=head;
                head=null;
                return nod;
            }else{
                Node nod=head;
                head=head.next;
                head.front=null;
                return nod;
            }
        }else{
            System.out.println("队列空了");
            return null;            
        }
    }
    
    public Node  del(){
        if(isEmpty()==false){
            Node nod = findvip();
            if(nod==null){
                
            Node temp=head;
            if(head.next!=null){
                Node node = head.next;
                node.front=null;
                head=node;                
            }else{
                head=null;
            }
            //head.front=null;
            temp.next=null;
            return temp;
            }else{
                if(nod==head){
                    nod=head;
                    head=null;
                    return nod;
                }else if(nod==tail){
                    Node tm = nod;
                    nod.front.next=null;
                    return tm;
                }else{
                    nod.front.next=nod.next;
                    nod.next.front=nod.front;
                    return nod;
                }
            }
        }else{
            System.out.println("队列空了");
            return null;
        }
    }
    
    public Node findvip(){
        if(isEmpty()==false){
            Node temp = head;
            while(temp!=null){
                if(temp.cus.key==0){
                    return temp;
                }
                temp = temp.next;
            }
        }
        return null;
    }
 
    
}
class Node{
    Custm cus;
    Node front;
    Node next;
    public Node(Custm c){
        cus =c;
        front = next = null;
    }
}

以下答案由GPT-4.0Plus大模型与博主A努力中.......共同编写:
从你的代码和描述来看,号码缺失的情况很有可能是由于多线程操作同一个Stack对象导致的。

具体来说:

  1. 你的ATM类中的四个线程都共享同一个Stack对象s,用于弹出下一个号码。

  2. 当多个线程同时执行s.pop()操作时,由于Thread schedular的调度,有可能导致某些号码被跳过,出现缺失。

要解决这个问题,有两种方法:

  1. 为每个ATM线程创建一个单独的Stack对象。这样每个线程只操作自己的Stack,不会有线程安全问题。
    修改后的代码如下:
java
ATM atm1=new ATM("服务机"); 
Stack s1 = new Stack();
atm1.s = s1;  
//...

  1. 使用synchronized关键字对Stack对象加锁,使得一次只有一个线程可以执行pop()操作。
    修改Stack类如下:
java
public class Stack {
    //...
    public synchronized int pop(){  
        //...
    }
}

这种方法对所有方法加锁,可能会影响效率。你也可以只对关键方法如pop()加锁。

除此之外,你还可以使用更高级的并发容器如BlockingQueue来实现这个功能,这可能会更高效和简洁。

总而言之,出现这个问题的关键是多线程同时访问和修改同一个共享资源,解决办法就是确保任意时刻只有一个线程在访问该资源。

可以借鉴下

package 排队;
 
public class Test01 {
    public static void main(String[] args){
        St  st = new St();
        Custm[] cus = new Custm[20];
        int[] ran = {1,1,1,0,1,0,1,1,1,0,1};
        //int[] ran = {1,0,1,1,0,1,0,1,0,1,1};
        for(int i=0;i<20;i++){
            int a = (int)(Math.random()*10);
            cus[i] = new Custm(i+1,ran[a]);
            st.add(cus[i]);
            
        }
        Worke wort = new Worke(st, "vip", true);//vip窗口,线程1
        Thread t1 = new Thread(wort);
        t1.start();
        
        Worke wort1 = new Worke(st, "1号" , false);//普通窗口,线程2,
        Thread t2 = new Thread(wort1);
        t2.start();
        
        Worke wort2 = new Worke(st, "2号" , false);//普通窗口,线程3,
        Thread t3 = new Thread(wort2);
        t3.start();
        Worke wort4 = new Worke(st, "3号" , false);//普通窗口,线程4,
        Thread t4 = new Thread(wort4);
        t4.start();
        
        
    }
}
class Custm{
    int key;
    int num;
    public Custm(int n, int k){
        num=n;
        key=k;
    }
}
 
class base {
    
}
class Worke implements Runnable{
    boolean isvip;
    St s;
    String ThreadName;
    public Worke(St ss,String n ,boolean vip){
        s=ss;
        ThreadName = n;
        isvip = vip;
    }
    boolean asd=true;
    public void run(){
        while(asd){
            if(s.isEmpty()==false){
                
                if(isvip){
            //        synchronized(this){
                        
                    Custm cu = s.dell().cus;
                    if(cu.key==0){
                        
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【vip】顾客准备!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客就绪!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客正在办理!");
                    try {
                        Thread.sleep((int)(Math.random()*500));
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客已离开-------!");
                    
                //    }else{
                        
                //        try {
            //                Thread.sleep((int)(Math.random()*500));
            //            } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
            //                e.printStackTrace();
            //            }
        //            }
                    }
                    
                }else{
            //        synchronized(this){
                        
                    Custm cu = s.dell().cus;
                    if(cu.key==0){
                        
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【vip】顾客准备!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客就绪!");
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客正在办理!");
                    try {
                        Thread.sleep((int)(Math.random()*500));
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【vip】顾客已离开-------!");
                    }else{
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口无人,请"+cu.num+"号【普通】顾客准备!");
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客就绪!");
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客正在办理!");
                        try {
                            Thread.sleep((int)(Math.random()*500));
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println("线程id" + Thread.currentThread().getId() +"\t"+ThreadName+"---窗口"+cu.num+"号【普通】顾客已离开-------!");
                        
                    }
            //        }
                    
                }
            }else{
                asd=false;
            }
            
        }
    }
}
class St{
    Node head;
    Node tail;
    public St(){
        tail=head=null;
    }
    public boolean isEmpty(){
        if(head==null){
            return true;
        }
        return false;
    }
    
    public void add(Custm c){
        Node node = new Node(c);
        if(isEmpty()){
            head=tail=node;
            head.front=null;
            tail.next=null;
        }else{
            tail.next=node;
            node.front=tail;
            tail=node;
            tail.next=null;
        }
    }
    public Node dell(){
        if(isEmpty()==false){
            if(head.next==null){
                Node nod=head;
                head=null;
                return nod;
            }else{
                Node nod=head;
                head=head.next;
                head.front=null;
                return nod;
            }
        }else{
            System.out.println("队列空了");
            return null;            
        }
    }
    
    public Node  del(){
        if(isEmpty()==false){
            Node nod = findvip();
            if(nod==null){
                
            Node temp=head;
            if(head.next!=null){
                Node node = head.next;
                node.front=null;
                head=node;                
            }else{
                head=null;
            }
            //head.front=null;
            temp.next=null;
            return temp;
            }else{
                if(nod==head){
                    nod=head;
                    head=null;
                    return nod;
                }else if(nod==tail){
                    Node tm = nod;
                    nod.front.next=null;
                    return tm;
                }else{
                    nod.front.next=nod.next;
                    nod.next.front=nod.front;
                    return nod;
                }
            }
        }else{
            System.out.println("队列空了");
            return null;
        }
    }
    
    public Node findvip(){
        if(isEmpty()==false){
            Node temp = head;
            while(temp!=null){
                if(temp.cus.key==0){
                    return temp;
                }
                temp = temp.next;
            }
        }
        return null;
    }
 
    
}
class Node{
    Custm cus;
    Node front;
    Node next;
    public Node(Custm c){
        cus =c;
        front = next = null;
    }
}

借鉴chatgpt4:
在编写多线程银行排队代码时,使用栈来赋值所取号码可能会出现竞争条件(race condition)的问题。竞争条件可在多个线程同时访问和修改共享变量时发生,导致预期之外的行为。

为了避免这种情况,您可以使用线程安全的数据结构,例如并发集合(concurrency collections)来存储号码。另外一种方法是使用同步机制,例如锁定(locks),以确保只有一个线程可以同时访问和修改共享变量。

重要的是要确保以确定性的方式为号码赋值,以避免序列中出现缺失或重复的情况。您可以通过使用原子计数器(atomic counter)或同步块(synchronized block)来增加和分配号码,从而实现此目的。