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相关知识。

  • 相关阅读:
    Android Studio 开发
    Jsp编写的页面如何适应手机浏览器页面
    电影
    Oracle 拆分列为多行 Splitting string into multiple rows in Oracle
    sql server 2008 自动备份
    WINGIDE 激活失败
    python安装 错误 “User installations are disabled via policy on the machine”
    ble编程-外设发送数据到中心
    iOS开发-NSString去掉所有换行及空格
    ios9 字符串与UTF-8 互相转换
  • 原文地址:https://www.cnblogs.com/wf-001128/p/12076615.html
Copyright © 2011-2022 走看看