zoukankan      html  css  js  c++  java
  • 201871010107-公海瑜《面向对象程序设计(java)》第十七周学习总结

          201871010107-公海瑜《面向对象程序设计(java)》第十七周学习总结

               项目                        内容
      这个作业属于哪个课程      https://www.cnblogs.com/nwnu-daizh/
      这个作业的要求在哪里   https://www.cnblogs.com/nwnu-daizh/p/12073034.html       
      作业学习目标

      (1) 理解和掌握线程的优先级属性及调度方法;

      (2) 掌握线程同步的概念及实现技术;

      (3) Java线程综合编程练习

    第一部分:总结线程同步技术

    1.Java通过多线程的并发运行提高系统资源利用率,改善系统性能。

    2.假设有两个或两个以上的线程共享某个对象,每个线程都调用了改变该对象类状态的方法,就会引起的不确定性。

    3.多线程并发执行中的问题

    ◆多个线程相对执行的顺序是不确定的。

    ◆线程执行顺序的不确定性会产生执行结果的不确定性。

    ◆在多线程对共享数据操作时常常会产生这种不确定性。

    4.多线程并发运行不确定性问题解决方案:引入线程同步机制。

       当多个线程访问同一个数据时,容易出现线程安全问题,需要某种方式来确保资源在某一时刻只被一个线程使用。需要让线程同步,保证数据安全。

       线程同步的实现方案:同步代码块和同步方法,均需要使用synchronized关键字

       线程同步的好处:解决了线程安全问题

       线程同步的缺点:性能下降,可能会带来死锁

    5.(1)锁对象与条件对象

               用ReentrantLock保护代码块的基本结构如下:

               myLock.lock();

               try { critical section }

               finally{

               myLock.unlock();

               }

       (2)synchronized关键字

              synchronized关键字作用:

             ➢ 某个类内方法用synchronized 修饰后,该方法被称为同步方法;

             ➢ 只要某个线程正在访问同步方法,其他线程欲要访问同步方法就被阻塞,直至线程从同步方法返回前唤醒被阻塞线程,其他线程方可能进入同步方法。

     6.Java中每个对象都有一个内置锁。

           当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁。获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。

          当程序运行到synchronized同步方法或代码块时才该对象锁才起作用。

          一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。

         释放锁是指持锁线程退出了synchronized同步方法或代码块。

    关于锁和同步,有一下几个要点:

    1)只能同步方法,而不能同步变量和类;

    2)每个对象只有一个锁;当提到同步时,应该清楚在什么上同步?也就是说,在哪个对象上同步?

    3)不必同步类中所有的方法,类可以同时拥有同步和非同步方法。

    4)如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。

    5)如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制。

    6)线程睡眠时,它所持的任何锁都不会释放。

    7)线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。

    8)同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块。

    9)在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁。例如:

        public int fix(int y) {

            synchronized (this) {

                x = x - y;

            }

            return x;

        }

    当然,同步方法也可以改写为非同步方法,但功能完全一样的,例如:

        public synchronized int getX() {

            return x++;

        }

        public int getX() {

            synchronized (this) {

                return x;

            }

        }

    效果是完全一样的。

    第二部分:实验部分

     实验1:测试程序并进行代码注释。

    测试程序1:

    l 在Elipse环境下调试教材651页程序14-7,结合程序运行结果理解程序;

    l 掌握利用锁对象和条件对象实现的多线程同步技术。

    程序代码:

    package synch;
    
    import java.util.*;
    import java.util.concurrent.locks.*;
    
    /**
     * A bank with a number of bank accounts that uses locks for serializing access.
     * @version 1.30 2004-08-01
     * @author Cay Horstmann
     */
    public class Bank
    {
       private final double[] accounts;  //银行运转的基本数据
       private Lock bankLock;  //锁对象
       private Condition sufficientFunds;
    
       /**
        * Constructs the bank.
        * @param n the number of accounts
        * @param initialBalance the initial balance for each account
        */
       public Bank(int n, double initialBalance)
       {
          accounts = new double[n];
          Arrays.fill(accounts, initialBalance);
          bankLock = new ReentrantLock();
          sufficientFunds = bankLock.newCondition();
       }
    
       /**
        * Transfers money from one account to another.
        * @param from the account to transfer from
        * @param to the account to transfer to
        * @param amount the amount to transfer
        */
       public void transfer(int from, int to, double amount) throws InterruptedException
       {
          bankLock.lock();
          try
          {  //锁对象的引用条件对象
             while (accounts[from] < amount)
                sufficientFunds.await();
             System.out.print(Thread.currentThread());  //打印出线程号
             accounts[from] -= amount;
             System.out.printf(" %10.2f from %d to %d", amount, from, to);
             accounts[to] += amount;
             System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
             sufficientFunds.signalAll();
          }
          finally
          {
             bankLock.unlock();
          }
       }
    
       /**
        * Gets the sum of all account balances.
        * @return the total balance
        */
       public double getTotalBalance()
       {
          bankLock.lock();  //加锁
          try
          {
             double sum = 0;
    
             for (double a : accounts)
                sum += a;
    
             return sum;
          }
          finally
          {
             bankLock.unlock();  //解锁
          }
       }
    
       /**
        * Gets the number of accounts in the bank.
        * @return the number of accounts
        */
       public int size()
       {
          return accounts.length;
       }
    }
    package synch;
    
    /**
     * This program shows how multiple threads can safely access a data structure.
     * @version 1.31 2015-06-21
     * @author Cay Horstmann
     */
    public class SynchBankTest
    {
       public static final int NACCOUNTS = 100;
       public static final double INITIAL_BALANCE = 1000;
       public static final double MAX_AMOUNT = 1000;
       public static final int DELAY = 10;
       
       public static void main(String[] args)
       {
          Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
          for (int i = 0; i < NACCOUNTS; i++)
          {
             int fromAccount = i;
             Runnable r = () -> {
                try
                {
                   while (true)
                   {
                      int toAccount = (int) (bank.size() * Math.random());
                      double amount = MAX_AMOUNT * Math.random();
                      bank.transfer(fromAccount, toAccount, amount);
                      Thread.sleep((int) (DELAY * Math.random()));
                   }
                }
                catch (InterruptedException e)
                {
                }            
             };
             Thread t = new Thread(r);
             t.start();
          }
       }
    }

    运行结果:

    测试程序2:

    l 在Elipse环境下调试教材655页程序14-8,结合程序运行结果理解程序;

    掌握synchronized在多线程同步中的应用。

    程序代码:

    package synch2;
    
    import java.util.*;
    
    /**
     * 具有多个使用同步原语的银行账户的银行。
     * @version 1.30 2004-08-01
     * @author Cay Horstmann
     */
    public class Bank
    {
       private final double[] accounts;
    
       /**
        * Constructs the bank.
        * @param n the number of accounts
        * @param initialBalance the initial balance for each account
        */
       public Bank(int n, double initialBalance)
       {
          accounts = new double[n];
          Arrays.fill(accounts, initialBalance);
       }
    
       /**
        * 把钱从一个账户转到另一个账户。
        * @param from the account to transfer from
        * @param to the account to transfer to
        * @param amount the amount to transfer
        */
       public synchronized void transfer(int from, int to, double amount) throws InterruptedException
       {
          while (accounts[from] < amount)
             wait(); //导致线程进入等待状态直到它被通知。该方法只能在一个同步方法中调用。
          System.out.print(Thread.currentThread());  //打印出线程号
          accounts[from] -= amount;
          System.out.printf(" %10.2f from %d to %d", amount, from, to);  //第一个打印结果保留两位小数(最大范围是十位),
          accounts[to] += amount;
          System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
          notifyAll();  //解除那些在该对象上调用wait方法的线程阻塞状态。该方法只能在同步方法或同步块内部调用。
       }
    
       /**
        * Gets the sum of all account balances.
        * @return the total balance
        */
       public synchronized double getTotalBalance()
       {
          double sum = 0;
    
          for (double a : accounts)
             sum += a;
    
          return sum;
       }
    
       /**
        * Gets the number of accounts in the bank.
        * @return the number of accounts
        */
       public int size()
       {
          return accounts.length;
       }
    }
    package synch2;
    
    /**
     * This program shows how multiple threads can safely access a data structure,
     * using synchronized methods.
     * @version 1.31 2015-06-21
     * @author Cay Horstmann
     */
    public class SynchBankTest2
    {
       public static final int NACCOUNTS = 100;
       public static final double INITIAL_BALANCE = 1000;
       public static final double MAX_AMOUNT = 1000;
       public static final int DELAY = 10;
    
       public static void main(String[] args)
       {
          Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
          for (int i = 0; i < NACCOUNTS; i++)
          {
             int fromAccount = i;
             Runnable r = () -> {
                try
                {
                   while (true)
                   {
                      int toAccount = (int) (bank.size() * Math.random());
                      double amount = MAX_AMOUNT * Math.random();
                      bank.transfer(fromAccount, toAccount, amount);
                      Thread.sleep((int) (DELAY * Math.random()));
                   }
                }
                catch (InterruptedException e)
                {
                }
             };
             Thread t = new Thread(r);
             t.start();
          }
       }
    }

     运行结果:

    测试程序3:

    l 在Elipse环境下运行以下程序,结合程序运行结果分析程序存在问题;

    l 尝试解决程序中存在问题。

    程序代码:

    class Cbank
    {
         private static int s=2000;
         public   static void sub(int m)
         {
               int temp=s;
               temp=temp-m;
              try {
                     Thread.sleep((int)(1000*Math.random()));
                   }
               catch (InterruptedException e)  {              }
                  s=temp;
                  System.out.println("s="+s);
              }
        }
    
    
    class Customer extends Thread
    {
      public void run()
      {
       for( int i=1; i<=4; i++)
         Cbank.sub(100);
        }
     }
    public class Thread3
    {
     public static void main(String args[])
      {
       Customer customer1 = new Customer();
       Customer customer2 = new Customer();
       customer1.start();
       customer2.start();
      }
    }

    运行截图:

    更正思路:增加语句 synchronized

    代码:

    class Cbank
    {
         private static int s=2000;
         public synchronized  static void sub(int m)
         {
               int temp=s;
               temp=temp-m;
              try {
                     Thread.sleep((int)(1000*Math.random()));
                   }
               catch (InterruptedException e)  {              }
                  s=temp;
                  System.out.println("s="+s);
              }
        }
    
    
    class Customer extends Thread
    {
      public void run()
      {
       for( int i=1; i<=4; i++)
         Cbank.sub(100);
        }
     }
    public class Thread3
    {
     public static void main(String args[])
      {
       Customer customer1 = new Customer();
       Customer customer2 = new Customer();
       customer1.start();
       customer2.start();
      }
    }

    运行结果:

    实验2 :编程练习

    利用多线程及同步方法,编写一个程序模拟火车票售票系统,共3个窗口,卖10张票,程序输出结果类似(程序输出不唯一,可以是其他类似结果)。

    Thread-0窗口售:第1张票

    Thread-0窗口售:第2张票

    Thread-1窗口售:第3张票

    Thread-2窗口售:第4张票

    Thread-2窗口售:第5张票

    Thread-1窗口售:第6张票

    Thread-0窗口售:第7张票

    Thread-2窗口售:第8张票

    Thread-1窗口售:第9张票

    Thread-0窗口售:第10张票

     程序代码:

    public class shoupiao {
        public static void main(String[] args) {
           thread1 mythread = new thread1();
            Thread ticket1 = new Thread(mythread);
            ticket1.start();
            Thread ticket2 = new Thread(mythread);
            ticket2.start();
            Thread ticket3 = new Thread(mythread);
            ticket3.start();
        }
    }
    
    class thread1 implements Runnable {
        int ticket = 1;
        boolean flag = true;
    
        @Override
        public void run() {
            while (flag) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
                synchronized (this) {
                    if (ticket <= 10) {
                        System.out.println(Thread.currentThread().getName() + "窗口售:第" + ticket + "张票");
                        ticket++;
                    }
                    if (ticket > 10) {
                        flag = false;
                    }
                }
            }
        }
    
    }

    运行截图:

    结对编程照片:

    实验总结:

            这次实验内容比较少,比较容易理解,通过这次的几个实验对线程同步有了进一步认识,对线程又有了更深的理解,课后要多花功夫理解才行。

  • 相关阅读:
    IIS的各种身份验证详细测试
    HTTP Error 401.3 Unauthorized Error While creating IIS 7.0 web site on Windows 7
    C/S and B/S
    WCF ContractFilter mismatch at the EndpointDispatcher exception
    Configure WCF
    Inheritance VS Composition
    Unhandled Error in Silverlight Application, code 2103 when changing the namespace
    Java RMI VS TCP Socket
    Principles Of Object Oriented Design
    Socket处理发送和接收数据包,一个小实例:
  • 原文地址:https://www.cnblogs.com/gonghaiyu/p/12088330.html
Copyright © 2011-2022 走看看