zoukankan      html  css  js  c++  java
  • 201871010121-王方-《面向对象程序设计java》第十七周学习总结

    项目

    内容

    这个作业属于哪个课程

    https://www.cnblogs.com/nwnu-daizh

    这个作业的要求在哪里

    https://www.cnblogs.com/nwnu-daizh/p/12073034.html

     

     作业学习目标

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

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

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

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

    一、synchronized关键字
    在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程锁拥有,当一个线程调用对象的一段synchronized代码时,需要先获取这个锁,然后去执行相应的代码,执行结束之后,释放锁。
    而synchronized关键字主要有两种用法:synchronized方法和synchronized块。此外,这个关键字还可以作用于静态方法、类或者某个实例,但这都对程序的效率有很大的影响。
    1.synchronized方法。在方法的声明前主要有synchronized关键字,示例如下:

     public synchronized void mutiThreadAccess();

    只要把多个线程对类需要被同步的资源的操作放到mutiThreadAccess()方法中,就能保证这个方法在同一时刻只能被同一个线程访问,从而保证了多线程访问的安全性。然而,当一个方法的方法体规模非常大时,把该方法声明为synchronized会大大影响程序的执行效率。为了提高程序的效率,Java提供了synchronized块。

     2.synchronized块

     synchronized块既可以把任意的代码段声明为synchronized,也可以指定上锁的对象。其用法如下:

    synchronized(syncObject){
    
       //访问synchObject的代码
    }
    二、wait()方法与notify()方法
    当使用synchronized来修饰某个共享资源时,如果线程A1在执行synchronized代码,另一个线程A2也要同时执行同一个对象的同一synchronized代码时,线程A2将要等到线程A1执行完成之后,才能继续执行。在这种情况下可以使用wait()方法和notify()方法。
    在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁,进入等待状态,并且可以调用notify()方法或者notifyAll()方法通知正在等待的其他线程。notify()方法仅唤醒一个线程(即等待队列中的第一个线程),并允许它去获得锁,notifyAll()方法唤醒所有等待这个对象的线程并允许他们去获得锁,但并不是让所有唤醒线程都去获取到锁,而是让他们去竞争。
    三、Lock
    JDK5新增加了Lock接口以及它的一个实现类ReentrantLock(重入锁),Lock也可以用来实现多线程的同步。具体而言,它提供了如下一些方法来实现多线程的同步:
    1.lock()。
    这个方法以阻塞的方式获取锁,也就是说,如果获取到锁了,立即返回;如果别的线程持有锁,当前线程就等待,知道获取到锁之后返回。
    2.tryLock()。
    这个方法与lock()方法不同,它以非阻塞的方式来获取锁。此外,它只是常识性地去获取一下锁,如果获取到了锁,立即返回true,否则立即返回false。
    3.tryLock(long timeout,TimeUnit unit)
    如果获取到锁,立即返回true,否则会等待参数给定的时间单元,在等待的过程中,如果获取到了锁,就返回true,如果等待超时则返回false。
    4.lockInterruptibly()
    如果获取了锁,立即返回;如果没有获取到锁,当前线程处于休眠状态,直到获取到锁,或者当前线程被别的线程中断(会受到InterruptedException异常)。它与lock()方法最大的区别在于如果lock()方法获取不到锁就会一直处于阻塞状态,而且还会忽略interrupt()方法。
    示例为:
    package javatest; 
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
        public class LockTest {     
        public static void main(String[] args)throws InterruptedException {        
    // TODO Auto-generated method stub        
        final Lock lock=new ReentrantLock();        
        lock.lock();        
        Thread t1=new Thread(new Runnable() {            
        public void run() {                
           try {                    
             lock.lockInterruptibly();                
             }
             catch(InterruptedException e)                
            {                             
                System.out.println("interrupted");                
             }            
           }        
     });        
           t1.start();        
           t1.interrupt();        
           Thread.sleep(1);    
    }
    }

    如果把lock.lockInterruptibly()替换为lock.lock(),编译器将会提示lock.lock()catch代码块无效,这是因为lock.lock()不会抛出异常,由此可见lock()方法会忽略interrupt()引发的异常。

     第二部分:实验总结

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

    测试程序1:

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

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

    程序源代码为:

    synch 

    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();//调用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();//调用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()));//调用sleep,随机
                   }
                }
                catch (InterruptedException e)//抛出异常
                {
                }            
             };
             Thread t = new Thread(r);//建立Thread类对象
             t.start();//启动线程
          }
       }
    }

     实验输出结果截图为:

     测试程序2:

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

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

     程序源代码为:

    package synch2;
    
    import java.util.*;
    
    /**
     * A bank with a number of bank accounts that uses synchronization primitives.
     * @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);
       }
    
       /**
        * 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 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

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

    尝试解决下列程序中的问题

    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();
      }
    }
    

     实验代码为:

    package wf;
    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(); } }

    实验输出结果截图为:

     程序修改代码后为:

    package wf;
    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张票

    实验代码为:

    package wf;
    
    import java.nio.charset.MalformedInputException;
    
    public class w {
        public  static void main(String[] args)
        {
            Mythread mythread=  new  Mythread();
            Thread t1 = new Thread(mythread);
            Thread t2 = new Thread(mythread);
            Thread t3 = new Thread(mythread);
            t1.start();
            t2.start();
            t3.start();
            
        }
        
        
    }
    
    class Mythread implements Runnable{
        
        int t=1;
        boolean flag=true;
         
        public void run() {
            
            while(flag) {
                try {
                    
                     Thread.sleep(500);
                      }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }            
                
                
                
                 synchronized  (this) {
                
                if(t<=10){
                    System.out.println(Thread.currentThread().getName()+"窗口售:第"+t+"张票");
                    t++;
                }
                if(t>10){
                  flag=false;    
                }
                
            }
            
        }
    }
    }

    实验输出结果截图为:

     第三部分 实验总结

         这周是我们上的最后一节java课,也预示着一学期的Java课结束了,但是课堂上的我们还是没有丝毫松懈。这周我们主要还是学习了有关线程方面更加重要的知识。有关线程并发执行中可能出现的各种问题,比如当有两个或者两个以上的线程共享某个对象,每个线程都调用了改变该对象类状态的方法时会初心什么情况。就这个问题,老师给我们展开了详细的解说。正如老师说的“这些问题都是我们在使用计算机的过程中真实会发生的情况”所以掌握这些知识是极其重要的。对于我个人而言,我觉得这节课掌握的相对较好的知识点是有关线程的状态这个方面,而且在这些知识点上老师通过图表讲解的非常详细。我以后也会继续好好学习Java相关知识。

  • 相关阅读:
    6.11 考试修改+总结
    6.10 考试修改+总结+颓废记
    我们都一样
    【HDU 5730】Shell Necklace
    【SPOJ 8093】Sevenk Love Oimaster
    【BZOJ 3238】【AHOI 2013】差异
    【UOJ #131】【NOI 2015】品酒大会
    【SPOJ 220】Relevant Phrases of Annihilation
    【POJ 3177】Redundant Paths
    【POJ 2186】Popular Cows
  • 原文地址:https://www.cnblogs.com/wf-001128/p/12076615.html
Copyright © 2011-2022 走看看