Java线程同步以及在同步方法中使用wait()/notify()/notifyAll()//磁盘调度

线程的同步

用户在处理多线程的时候,变量有可能被多个线程共享,简单举一个例子,就是当一个工资负责人正在使用账本出账的是时候,一个员工也要使用账本来领取工资,这时情况就是工资未出账完成就被领取了,这就造成混乱.

为了解决类似的问题Java就作出了线程同步的方法,就是用synchronized关键字修饰一个方法,当这个方法被synchronized关键字修饰后,线程调用这个方法时就不会被打扰,也就是另一个线程要等待线程执行完该方法后才能到自己执行该方法.

总的来说,所谓线程同步就是若干个线程使用synchronized关键字修饰的方法

结合出账例子

package Chapter_15.Part_4;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class myWindow extends JFrame implements ActionListener {
    Bank bank;
    Thread thread1;
    Thread thread2;
    JTextArea jTextArea1;
    JTextArea jTextArea2;
    JButton jButton;

    public myWindow() {
        bank = new Bank();
        thread1 = new Thread(bank);
        thread1.setName("存");
        thread2 = new Thread(bank);
        thread2.setName("取");
        setBounds(500, 500, 500, 500);
        setLayout(new FlowLayout());
        setTitle("演示");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        jButton = new JButton("开始演示");
        jButton.addActionListener(this);
        add(jButton);
        jTextArea1 = new JTextArea(5, 16);
        add(new JScrollPane(jTextArea1));
        jTextArea2 = new JTextArea(5, 16);
        add(new JScrollPane(jTextArea2));
        bank.setMoney(100);
        bank.setText1(jTextArea1, jTextArea2);
        validate();
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        if (thread1.isAlive() == false && thread2.isAlive() == false) {
            thread1 = new Thread(bank);
            thread1.setName("存");
            thread2 = new Thread(bank);
            thread2.setName("取");
            bank.setMoney(100);
            jTextArea1.setText(null);   //清空
            jTextArea2.setText(null);   //清空
        }
        try {
            thread1.start();
            thread2.start();
        } catch (Exception e) {
        }
    }
}

package Chapter_15.Part_4;

import javax.swing.*;

public class Bank implements Runnable {
    JTextArea jTextArea1;
    JTextArea jTextArea2;
    int money;
    String name;

    public void setText1(JTextArea text1, JTextArea text2) {
        this.jTextArea1 = text1;
        this.jTextArea2 = text2;

    }

    public void setMoney(int money) {
        this.money = money;
    }

    public synchronized void Access(int x) {
        if (name.equals("存")) {
            for (int i = 0; i < 3; i++) {
                money = money + x;
                jTextArea1.append("现在存" + x + "元" + "当前余额:" + money + "\n");
                try {
                    Thread.sleep(1000); //      存一次喝口茶
                } catch (InterruptedException e) {
                }
            }
            jTextArea1.append("存钱完毕!");
        } else if (name.equals("取")) {
            for (int i = 0; i < 3; i++) {
                money = money - x;
                jTextArea2.append("现在取" + x + "元" + "当前余额:" + money + "\n");
                try {
                    Thread.sleep(1000); //      存一次喝口茶
                } catch (InterruptedException e) {
                }
            }
            jTextArea2.append("取钱完毕!");
        }
    }

    @Override
    public void run() {
        name = Thread.currentThread().getName();
        if (name.equals("存")) {
            Access(100);
        } else if (name.equals("取")) {
            Access(10);
        }

    }
}

package Chapter_15.Part_4;

public class Example15_10 {
    public static void main(String[] args) {
        myWindow myWindow = new myWindow();
    }
}

运行效果图
在这里插入图片描述

在同步方法中使用wait()/notify()/notifyAll()

由于当一个线程在方法同步的方法时另一个线程不能进行访问,但是当同步方法中的变量需要被改变后才能满足线程的需要,那么这时候就会出现死锁的情况

就好比如售票员卖票,你去买票,你拿了100块钱买票,售票员恰好没有零钱找赎,那么你就一直在等,同时你又不让后面的人买票,从而导致你又收不到零钱,后面的人又买不到票的情况

所以Java就提供了可以在同步方法中使用wait()/notify()/notifyAll(),从而解决死锁问题
使用wait()方法可以中断方法的执行,从而让另外的线程访问同步方法,建议在while()方法中执行
使用notify()方法是通时之前某一个线程继续执行上一次中断处未执行的方法
使用notifyAll()方法是通知所有中断过的线程再次执行中断处未执行下去的方法

wait()/notify()/notifyAll()都是Object类的final方法,不允许重写

两个线程实现猜数字的例子

package Chapter_15.Part_5;

public class Number implements Runnable {
    final int SMALLER = -1, LARGER = 1, SUCCESS = 8;
    int realNumber, guessNumber, min = 0, max = 100, message = SMALLER;
    boolean pleaseGuess = false, isGiveNumber = false;
    Thread threadGive;
    Thread threadGuess;

    Number() {
        threadGive = new Thread(this);
        threadGuess = new Thread(this);
        threadGive.start();
        threadGuess.start();
    }

    @Override
    public void run() {
        for (int count = 1; true; count++) { //count是得知猜了多少次
            setMessage(count);
            if (message == SUCCESS) {
                return;
            }
        }
    }

    public synchronized void setMessage(int count) {
        if (Thread.currentThread() == threadGive && isGiveNumber == false) {
            realNumber = (int) (Math.random() * 10);   //获取一个0-99的数
            System.out.println("给你一个0-99的数猜猜");
            isGiveNumber = true;
            pleaseGuess = true;
        }
        if (Thread.currentThread() == threadGive) {
            while (pleaseGuess == true)
                try {
                    wait(); //让出CPU让转到另一个线程
                } catch (InterruptedException e) {
                }
            if (guessNumber < realNumber) {
                message = SMALLER;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                System.out.println("你猜小了!");
            } else if (guessNumber > realNumber) {
                message = LARGER;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                System.out.println("你猜大了!");
            } else {
                message = SUCCESS;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                System.out.println("恭喜你猜对了!!");
            }
            pleaseGuess = true;
        }

        if (Thread.currentThread() == threadGuess && isGiveNumber == true) {
            while (pleaseGuess == false)
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            if (message == SMALLER) {
                min = guessNumber;
                guessNumber = (min + max) / 2;
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                System.out.println("我第" + count + "次猜这个数是" + guessNumber);
            } else if (message == LARGER) {
                max = guessNumber;
                guessNumber = (min + max) / 2;
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                System.out.println("我第" + count + "次猜这个数是" + guessNumber);
            }
            pleaseGuess = false;
        }
        notifyAll();
    }
}

package Chapter_15.Part_5;

public class Example15_11 {
    public static void main(String[] args) {
        Number number = new Number();
    }
}

运行效果

C:\Users\Administrator\.IntelliJIdea2019.3\config\jdbc-drivers\Apache Derby\10.14.1.0\derby-10.14.1.0.jar" Chapter_15.Part_5.Example15_11
给你一个0-99的数猜猜
我第1次猜这个数是50
你猜大了!
我第2次猜这个数是25
你猜大了!
我第3次猜这个数是12
你猜大了!
我第4次猜这个数是6
你猜大了!
我第5次猜这个数是3
你猜大了!
我第6次猜这个数是1
你猜大了!
我第7次猜这个数是0
恭喜你猜对了!!

进程已结束,退出代码 0

磁盘调度

磁盘调度的目的是使平均寻道时间最少

磁盘驱动调度

  • 先来先服务

先来先服务算法(FCFS)按照访问请求的次序为各个进程服务,这是最公平且最简单的算法,但是效率不高

  • 最短寻道时间优先算法

最短寻道时间优先算法(SSTF)以寻道优化为出发点,优先为距离磁头当前所在位置盘近的磁道(柱面)的访问请求服务。这种算法使每次的寻道时间最短,但也存在缺点:不能保证平均寻道时间最短。

  • 扫描算法

扫描算法(SCAN)也是一种寻道优化的算法,它克服了SSTF算法的缺点,既考虑访问磁道与磁头当前位置的距离,又考虑磁臂的移动方向,且以方向优先。这种笔法比较公平,而且效率较高。这种算法因其基本思想与电梯的工作原理相似,故又称电梯算法。

  • 单向扫描调度算法

单向扫描调度算法(CSCAN)存在这样的问题:当磁头刚从里向外移动过某一磁道时,恰有一进程请求访问此磁道,这时该进程必须等待磁头从里向外,然后再从外向里扫描完所有要访问的磁道后,才处理该进程的请求,致使该进程的请求被严重地推迟。为了减少这种延迟,CSCAN算法规定磁头作单向移动。

旋转调度算法

系统应该选择延迟时间最短的进程对磁盘的扇区进行访问。当有若干等待进程请求访问磁盘上的信息时,旋转调度应考虑以下三种情况。
1.进程请求访问的是同一磁道上的不同编号的扇区。
2.进程请求访问的是不同磁道上的不同编号的扇区。
3.进程请求访问的是不同磁道上具有相同编号的扇区。

CET4P198

  • voltage
  • volume
  • volt
  • activity
  • standpoint
  • liberate
  • device
  • canal
  • angle
  • arrange
  • voluntary
  • rhythm
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值