【Java实现】WHUT操作系统实验(动态分区管理+磁盘调度)

2021/12/27 20:37:22

本文主要是介绍【Java实现】WHUT操作系统实验(动态分区管理+磁盘调度),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

备个份

动态分区管理:

Course:

public class Course { //进程类
    private String desc; //进程描述
    private int spaces; //进程所需内存大小
    private Space matchspace; //进程运行时所占的内存分区
    public Course(){}
    public Course(int spaces,String desc){
        this.spaces=spaces;
        this.desc=desc;
        matchspace=null;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public int getSpaces() {
        return spaces;
    }
    public void setSpaces(int spaces) {
        this.spaces = spaces;
    }
    public Space getMatchspace() {
        return matchspace;
    }
    public void setMatchspace(Space matchspace) {
        this.matchspace = matchspace;
    }
    public int compareTo(Course b){
        return Integer.compare(this.spaces,b.spaces);
    }
}

Space:

public class Space { //内存分区类
    private int size; //内存分区大小
    private int headAddr; //内存分区首地址
    private Status status; //内存分区状态
    public Space(){}
    public Space(int size,int headAddr){
        this.size=size;
        this.headAddr=headAddr;
        this.status=Status.FREE;
    }
    public Space(int size,int headAddr,Status status){
        this.size=size;
        this.headAddr=headAddr;
        this.status=status;
    }
    public Status getStatus() {
        return status;
    }
    public void setStatus(Status status) {
        this.status = status;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    public int getHeadAddr() {
        return headAddr;
    }
    public void setHeadAddr(int headAddr) {
        this.headAddr = headAddr;
    }
    public int compareTo(Space b,Methods x){ //空闲分区比较器
        if(x==Methods.BEST) { //最佳适应法,比较内存分区大小,由小到大
            return Integer.compare(this.size,b.size);
        }
        else if(x==Methods.FIRST){ //最先适应法,比较内存分区首地址,由小到大
            return Integer.compare(this.headAddr,b.headAddr);
        }
        else{ //最坏适应法,比较内存分区大小,由大到小
            return -(Integer.compare(this.size,b.size));
        }
    }
}

Methods / Status:

enum Methods { //内存算法
    FIRST("最先适应法"),
    BEST("最佳适应法"),
    WORST("最坏适应法");
    private final String desc;
    private Methods(String desc){
        this.desc=desc;
    }
}
enum Status{ //内存分区使用状态
    FREE("空闲分区"),
    USING("已使用分区"),
    EMPTY("空表目");
    private final String desc;
    private Status(String desc){
        this.desc=desc;
    }
}

Main:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    public static Main test=new Main();
    public static Scanner scan=new Scanner(System.in);
    public static LinkedList<Space> spaceList=new LinkedList<>(); //保存内存分区信息
    public static ArrayList<Course> courseList=new ArrayList<>(); //保存已添加未分配的进程信息
    public static ArrayList<Course> usingList=new ArrayList<>(); //保存已分配未回收的进程信息
    public static int ROM;
    public static Methods METHOD;
    public void switchROM(){
        System.out.println("-----修改内存大小-----");
        System.out.print("新的内存大小为(会清空当前所有已分配进程):");
        ROM=scan.nextInt();
        spaceList.clear();
        spaceList.add(new Space(ROM,0,Status.FREE));
        for(Course a:usingList){
            a.setMatchspace(null);
            courseList.add(a);
        }
        usingList.clear();
    }
    public void switchMETHOD() {
        System.out.println("-----修改分配算法-----");
        System.out.println("1:最先适应法(按首地址从小到大排序)");
        System.out.println("2:最佳适应法(按分区空间从小到大排序)");
        System.out.println("3:最坏适应法(按分区空间从大到小排序)");
        System.out.println("0:取消");
        System.out.print("新的分配算法为:");
        switch (scan.nextInt()) {
            case 1 -> {
                METHOD = Methods.FIRST;
                break;
            }
            case 2 -> {
                METHOD = Methods.BEST;
                break;
            }
            case 3 -> {
                METHOD = Methods.WORST;
                break;
            }
            case 0->{
                return;
            }
        }
    }
    public void addCOURSE(){
        int addROM=0;
        String addDesc="";
        System.out.println("-----添加进程-----");
        System.out.print("添加进程的数量为:");
        int addNum=scan.nextInt();
        int stepNum=0;
        while(++stepNum<=addNum){
            System.out.print("("+stepNum+"/"+addNum+") 占用空间(-1退出):");
            addROM=scan.nextInt();
            if(addROM==-1){
                return;
            }
            System.out.print("("+stepNum+"/"+addNum+") 进程描述(-1退出):");
            addDesc=scan.next();
            if(addDesc.equals("-1")){
                return;
            }
            courseList.add(new Course(addROM,addDesc));
        }
    }
    public void selectrunCOURSE(){
        System.out.println("-----分配进程-----");
        if(courseList.size()==0){
            System.out.println("尚未添加进程,分配失败");
            return;
        }
        courseList.sort(Course::compareTo);
        System.out.println("已添加的进程如下:");
        int courseNum=1;
        System.out.println("编号:\t占用空间:\t进程描述:");
        for (Course iter : courseList) {
            System.out.println(courseNum+"\t\t"+iter.getSpaces()+"\t\t\t"+iter.getDesc());
            courseNum++;
        }
        int courseSign=-1;
        while(courseSign<=0||courseSign>courseList.size()){
            System.out.print("选择要分配的进程编号(-1退出):");
            courseSign=scan.nextInt();
            if(courseSign==-1){
                return;
            }
        }
        runCOURSE(courseList.get(courseSign-1));
    }
    public void selectrestoreCOURSE(){
        System.out.println("-----回收进程-----");
        if(usingList.size()==0){
            System.out.println("尚未分配进程,回收失败");
            return;
        }
        System.out.println("已分配的进程如下");
        int courseNum=1;
        System.out.println("编号:\t进程描述:\t内存首地址:\t占用空间:");
        usingList.sort(Comparator.comparingInt(a -> a.getMatchspace().getHeadAddr()));
        for(Course iter:usingList){
            System.out.println(courseNum+"\t\t"+iter.getDesc()+"\t\t"+iter.getMatchspace().getHeadAddr()+"\t\t\t"+iter.getSpaces());
            courseNum++;
        }
        int courseSign=-1;
        while(courseSign<=0||courseSign>usingList.size()){
            System.out.print("选择要回收的进程编号(-1退出):");
            courseSign=scan.nextInt();
            if(courseSign==-1){
                return;
            }
        }
        restoreCOURSE(usingList.get(courseSign-1));
    }
    public void runCOURSE(Course x){
        if(spaceList.size()>1){
            spaceList.sort((a,b)->a.compareTo(b,METHOD));
        }
        for(Space iter:spaceList){
            if(iter.getStatus()==Status.FREE){ //要求分区尚未被分配给进程
                if(iter.getSize()==x.getSpaces()){ //存在与进程所占空间相同的分区
                    x.setMatchspace(iter); //分配该分区给进程
                    usingList.add(x); //进程添加进已分配集合,从未分配集合中删除
                    courseList.remove(x);
                    spaceList.get(spaceList.indexOf(iter)).setStatus(Status.USING); //改变该分区状态为已使用
                    System.out.println("分配成功 首地址:"+spaceList.get(spaceList.indexOf(iter)).getHeadAddr()+" 占用空间:"+spaceList.get(spaceList.indexOf(iter)).getSize());
                    return;
                }
                else if(iter.getSize()>x.getSpaces()){ //存在比进程所占空间更大的分区
                    //分为两个分区,上分区分配给进程(状态为已使用),下分区作为空闲分区
                    Space newspaceA=new Space(x.getSpaces(),iter.getHeadAddr(),Status.USING);
                    Space newspaceB=new Space(iter.getSize()-x.getSpaces(),iter.getHeadAddr()+x.getSpaces());
                    x.setMatchspace(newspaceA); //分配上分区给进程
                    usingList.add(x); //程添加进已分配集合,从未分配集合中删除
                    courseList.remove(x);
                    spaceList.remove(iter); //由于空闲分区被切割,删除原有分区,加入被分割的两个分区
                    spaceList.add(newspaceA);
                    spaceList.add(newspaceB);
                    System.out.println("分配成功 首地址:"+newspaceA.getHeadAddr()+" 占用空间:"+newspaceA.getSize());
                    return;
                }
            }
        }
        System.out.println("分配失败,请检查剩余内存大小");
    }
    public void restoreCOURSE(Course x){
        spaceList.sort((a,b)->a.compareTo(b, Methods.FIRST));
        int waitsign=spaceList.indexOf(x.getMatchspace()); //回收内存分区在链表中的所在位置
        x.setMatchspace(null); //将内存分区与进程分离
        usingList.remove(x); //进程回收,从已分配集合中删除,添加进未分配集合
        courseList.add(x);
        //第一种情况:
        //  不是首项&&不是最末项
        //  上下均有相邻的空闲分区
        if(waitsign!=(spaceList.size()-1)&&waitsign!=0&&spaceList.get(waitsign+1).getStatus()==Status.FREE&&spaceList.get(waitsign-1).getStatus()==Status.FREE){
            //改变上相邻分区的信息,作为合并后的大分区,删除余下的表项
            //此处将回收分区作为隐藏的表项存储在集合中,因此也要做删除操作,余下同理
            spaceList.get(waitsign-1).setSize(spaceList.get(waitsign-1).getSize()+spaceList.get(waitsign+1).getSize()+spaceList.get(waitsign).getSize());
            spaceList.remove(waitsign);
            spaceList.remove(waitsign);
        }
        //第二种情况:
        //  不是最末项
        //  只有下相邻的空闲分区
        else if(waitsign!=(spaceList.size()-1)&&spaceList.get(waitsign+1).getStatus()==Status.FREE){
            //改变下相邻分区信息(大小、首地址),删除余下的表项
            spaceList.get(waitsign).setSize(spaceList.get(waitsign).getSize()+spaceList.get(waitsign+1).getSize());
            spaceList.remove(waitsign+1);
            spaceList.get(waitsign).setStatus(Status.FREE);
        }
        //第三种情况:
        //  不是首项
        //  只有上相邻的空闲分区
        else if(waitsign!=0&&spaceList.get(waitsign-1).getStatus()==Status.FREE){
            //改变上相邻分区信息(大小),删除余下的表项
            spaceList.get(waitsign-1).setSize(spaceList.get(waitsign-1).getSize()+spaceList.get(waitsign).getSize());
            spaceList.remove(waitsign);
        }
        //第四种情况:
        //  没有相邻的空闲分区
        else{
            //建立新表项(更改自己分区的状态即可)
            spaceList.get(waitsign).setStatus(Status.FREE);
        }
        //打印回收成功信息
    }
    public void seeROM(){
        System.out.println("-----查看内存分配情况-----");
        System.out.println("当前的内存空间容量为:"+ROM);
        System.out.println("正在占用内存空间的进程:");
        System.out.println("进程描述:\t内存首地址:\t占用空间:");
        usingList.sort(Comparator.comparingInt(a -> a.getMatchspace().getHeadAddr()));
        for(Course iter:usingList){
            System.out.println(iter.getDesc()+"\t\t"+iter.getMatchspace().getHeadAddr()+"\t\t\t"+iter.getSpaces());
        }
        System.out.println("空闲的内存空间:");
        System.out.println("内存首地址:\t空间大小:");
        spaceList.sort((a,b)->a.compareTo(b, Methods.FIRST));
        for(Space iter:spaceList){
            if(iter.getStatus()==Status.FREE){
                System.out.println(iter.getHeadAddr()+"\t\t\t"+iter.getSize());
            }
        }
    }
    public static void main(String[] args) {
        System.out.println("-----动态分区管理初始化-----");
        test.switchROM();
        test.switchMETHOD();
        while(true){
            System.out.println("-----动态分区管理主菜单-----");
            System.out.println("1:修改内存大小(会清空当前所有已分配进程)");
            System.out.println("2:修改分配算法");
            System.out.println("3:添加进程");
            System.out.println("4:分配进程(需要先添加进程)");
            System.out.println("5:回收进程(需要先分配进程)");
            System.out.println("6:查看内存分配情况");
            System.out.println("7:还原初始状态");
            System.out.println("0:退出");
            System.out.print("选择功能编号:");
            switch(scan.nextInt()){
                case 1->{
                    test.switchROM();
                    break;
                }
                case 2->{
                    test.switchMETHOD();
                    break;
                }
                case 3->{
                    test.addCOURSE();
                    break;
                }
                case 4->{
                    test.selectrunCOURSE();
                    break;
                }
                case 5->{
                    test.selectrestoreCOURSE();
                    break;
                }
                case 6->{
                    test.seeROM();
                    break;
                }
                case 7->{
                    spaceList.clear();
                    courseList.clear();
                    usingList.clear();
                    spaceList.add(new Space(ROM,0,Status.FREE));
                    System.out.println("-----还原成功-----");
                    break;
                }
                case 0->{
                    return;
                }
            }
        }
    }
}

磁盘调度:

Loca:

public class Loca { //特殊序列类
    private int position; //请求序列元素位置
    private int front; //在当前磁头的移动方向之前还是之后
    public Loca(){}
    public Loca(int position){
        this.position=position;
    }
    public Loca(int position,int front){
        this.position=position;
        this.front=front;
    }
    public int getPosition() {
        return position;
    }
    public void setPosition(int position) {
        this.position = position;
    }
    public int getFront() {
        return front;
    }
    public void setFront(int front) {
        this.front = front;
    }
    public int compareTo(Loca b,int POSITION){ //比较器
        if(this.front!=b.front){ //如果方向不同,与磁头移动方向相同的排在前面
            return -Integer.compare(this.front,b.front);
        }
        //如果方向相同,与磁头距离更短的排在前面
        return Integer.compare(Math.abs(this.position-POSITION),Math.abs(b.position-POSITION));
    }
}

Direction:

enum Direction {
    BEHIND("沿磁道号减小的方向移动"),
    FRONT("沿磁道号增加的方向移动");
    private final String desc;
    private Direction(String desc){
        this.desc=desc;
    }
}

Main:

import java.security.Signature;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;

public class Main {
    public static Scanner scan=new Scanner(System.in);
    public static int ORIGINP; //初始磁头位置(只有重新设置才能改变)
    public static int POSITION; //当前磁头位置(随序列运行而改变)
    public static Direction DIRECTION; //磁头移动方向
    public static ArrayList<Integer> SignList=new ArrayList<>(); //保存请求序列
    public static Main test=new Main();
    public void SetPOSITION(){
        System.out.println("-----设置磁头位置-----");
        System.out.print("请输入新的磁头位置:");
        ORIGINP=scan.nextInt();
        POSITION=ORIGINP;
    }
    public void SetArray(){
        System.out.println("-----增加磁道访问请求序列-----");
        System.out.print("输入序列(以空格分割,-1结束):");
        int set=0,time=0;
        while(true){
            set=scan.nextInt();
            if(set!=-1){
                SignList.add(set);
            }
            else{
                break;
            }
            time++;
        }
        if(time>0){
            test.PrintArray();
        }
    }
    public void PrintArray(){
        System.out.println("当前的请求序列为:");
        for(int i=0;i<SignList.size();++i){
            System.out.print(i+1+"\t");
        }
        System.out.println();
        for(int i=0;i<SignList.size();++i){
            System.out.print(SignList.get(i)+"\t");
        }
        System.out.println();
    }
    public void DeleteArray(){
        System.out.println("-----修改磁道访问请求序列-----");
        if(SignList.size()==0){
            System.out.println("修改失败,请先添加访问请求序列");
            return;
        }
        test.PrintArray();
        int sign=0,set=0;
        System.out.print("输入要修改的编号(-1退出):");
        sign=scan.nextInt();
        if(sign==-1){
            return;
        }
        System.out.print("输入要修改的值(-1删除):");
        set=scan.nextInt();
        if(set==-1){
            SignList.remove(sign-1);
        }
        else{
            SignList.set(sign-1,set);
        }
    }
    public void RemoveArray(){
        System.out.println("-----清空序列-----");
        System.out.println("正在清空序列...");
        SignList.clear();
        System.out.println("正在还原磁头位置...");
        POSITION=ORIGINP;
    }
    public void StartTesting(){
        System.out.println("-----开始模拟调度-----");
        if(SignList.size()==0){
            System.out.println("调度失败,请先添加访问请求序列");
            return;
        }
        test.PrintArray();
        System.out.print("选择调度算法(1:FCFS,2:SSTF,3:SCAN,-1退出):");
        switch(scan.nextInt()){
            case 1->{
                test.FCFSme();
                POSITION=ORIGINP;
                break;
            }
            case 2->{
                test.SSTFme();
                POSITION=ORIGINP;
                break;
            }
            case 3->{
                System.out.print("请输入磁头初始移动方向(1:沿磁道号增大 2:沿磁道号减小):");
                switch(scan.nextInt()){
                    case 1->{
                        DIRECTION=Direction.FRONT;
                        break;
                    }
                    case 2->{
                        DIRECTION=Direction.BEHIND;
                    }
                }
                test.SCANme();
                POSITION=ORIGINP;
                break;
            }
            case -1->{
                return;
            }
        }
    }
    public void FCFSme(){
        System.out.println("---开始调度(FCFS先来先服务算法)---");
        float Movement=0; //磁头总移动
        for(int i=0;i<SignList.size();++i){ //共循环N次
            int set=SignList.get(i);
            System.out.print("第"+(i+1)+"次 原磁头:"+POSITION
                            +"\t下一个:"+set
                            +"\t移动数:"+Math.abs(POSITION-set)); //移动数取绝对值
            Movement+=Math.abs(POSITION-set);
            POSITION=set; //设置移动后的新磁头位置
            System.out.println();
        }
        System.out.println("总寻道长度:"+Movement+"\n平均寻道长度:"+Movement/SignList.size());
        System.out.println("-----调度完成-----");
    }
    public void SSTFme(){ //主方法
        System.out.println("---开始调度(SSTF最短寻道时间算法)---");
        float Movement=0; //磁头总移动
        //由于磁头位置会变,要对元素作删除操作,这里作复制操作,以便不影响原序列
        ArrayList<Integer> SSTFArray = new ArrayList<>(SignList);
        for(int i=0;i<SignList.size();++i) {
            SSTFArray.sort(this::SSTFcp); //按距离当前磁头位置的绝对值排序
            int set=SSTFArray.get(0); //同样取第0个,也就是经排序后的最小元素
            System.out.print("第"+(i+1)+"次 原磁头:"+POSITION
                            +"\t下一个:"+set
                            +"\t移动数:"+Math.abs(set-POSITION)); //移动数取绝对值
            Movement+=Math.abs(set-POSITION);
            POSITION=set; //设置移动后的新磁头位置
            SSTFArray.remove(0); //删除元素,使得排序后的0号元素始终是最佳的
            System.out.println();
        }
        System.out.println("总寻道长度:"+Movement+"\n平均寻道长度:"+Movement/SignList.size());
        System.out.println("-----调度完成-----");
    }
    public int SSTFcp(Integer a,Integer b){ //排序器
        return Integer.compare(Math.abs(a-POSITION),Math.abs(b-POSITION)); //比较绝对值
    }
    public void SCANme(){
        System.out.println("---开始调度(SCAN扫描算法/电梯算法)---");
        float Movement=0; //磁头总移动
        ArrayList<Loca> LocaList=new ArrayList<>();
        for(int i=0;i<SignList.size();++i){
            LocaList.add(new Loca(SignList.get(i))); //同SSTF算法,复制序列
        }
        for(int i=0;i<SignList.size();++i){
            for(int j=0;j<LocaList.size();++j){
                //复制过来的序列没有front属性,逐个与磁头位置比较并设置
                //共有两种情况front属性=-1:①磁头增加方向,比磁头位置小
                //                      ②磁头减少方向,比磁头位置大
                if(LocaList.get(j).getPosition()<POSITION&&DIRECTION==Direction.FRONT){
                    LocaList.get(j).setFront(-1);
                }
                else if(LocaList.get(j).getPosition()>POSITION&&DIRECTION==Direction.BEHIND){
                    LocaList.get(j).setFront(-1);
                }
                else{
                    LocaList.get(j).setFront(1);
                }
            }
            LocaList.sort((a,b)-> a.compareTo(b,POSITION)); //使用排序器对序列排序
            int set=LocaList.get(0).getPosition(); //取0号元素(最佳)
            System.out.print("第"+(i+1)+"次 原磁头:"+POSITION
                            +"\t下一个:"+set
                            +"\t移动数:"+Math.abs(set-POSITION)); //移动数采用绝对值
            Movement+=Math.abs(set-POSITION);
            //如果下一个最佳的与磁头方向相反,要改变磁头移动方向
            if(set<POSITION&&DIRECTION==Direction.FRONT){
                DIRECTION=Direction.BEHIND;
            }
            else if(set>POSITION&&DIRECTION==Direction.BEHIND){
                DIRECTION=Direction.FRONT;
            }
            POSITION=set; //移动磁头位置`
            LocaList.remove(0); //同SSTF算法,保证0号元素一定是当前的最佳元素
            System.out.println();
        }
        System.out.println("总寻道长度:"+Movement+"\n平均寻道长度:"+Movement/SignList.size());
        System.out.println("-----调度完成-----");
    }
    public static void main(String[] args) {
        System.out.println("-----磁盘调度系统-----");
        System.out.println("-----初始化-----");
        test.SetPOSITION();
        while(true){
            System.out.println("-----磁盘调度系统-----");
            System.out.println("1:设置磁头位置");
            System.out.println("2:添加磁道访问请求序列");
            System.out.println("3:修改磁道访问请求序列");
            System.out.println("4:开始模拟调度");
            System.out.println("5:清空序列");
            System.out.println("0:退出");
            System.out.print("输入功能序号:");
            switch(scan.nextInt()){
                case 1->{
                    test.SetPOSITION();
                    break;
                }
                case 2->{
                    test.SetArray();
                    break;
                }
                case 3->{
                    test.DeleteArray();
                    break;
                }
                case 4->{
                    test.StartTesting();
                    break;
                }
                case 5->{
                    test.RemoveArray();
                    break;
                }
                case 0->{
                    return;
                }
            }
        }
    }
}


这篇关于【Java实现】WHUT操作系统实验(动态分区管理+磁盘调度)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程