20189217 2018-2019-2 《移动平台开发实践》第5周学习总结

教材学习内容总结

第16章要点:

要点1:创建Path实例

创建Path实例的两种方法:

Path path1 = Paths.get("/home/user/images");
Path path2 = Paths.get("/home","user","images");  

创建一个Path实例,并不会创建一个物理的文件或路径。通常,Path实例引用不存在的物理对象。要创建一个文件或目录,需要使用File类。

要点2:文件和目录的处理和操作

创建文件:

public static Path createFile(Path file, java.nio.file.attribute.FileAttribute<?>... attrs)
// attrs参数可选

创建目录:

public static Path createDirectory(Path directory, java.nio.file.attribute.FileAttribute<?>... attrs)
// attrs参数可选

删除文件/目录/符号链接:

public static void delete(Path path)   
// 如果path是目录,那么,这个目录必须为空

获取一个目录对象:

public static DirectoryStream<Path> newDirectoryStream(Path path)   
// 返回一个DirectoryStream实例来遍历一个目录中的所有对象 

要点3:输入/输出流

java.io包中有4个抽象类来表示输入输出流:

  • Reader:从一个池中读取字符的流。
  • Writer:向一个池写入数据的流。
  • InputStream:从一个池中读取二进制数据的流。
  • OutputStream:向一个池写入二进制数据的流。

第19章要点:

要点1:创建线程

创建线程方法1:扩展java.lang.Thread

继承Thread类,重写该类的run()方法。

创建线程方法2:实现java.lang.Runnable

实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。

Runnable中的run方法和Thread类中的run方法使相同的。实际上,Thread自身实现了Runnable.

要点2:线程优先级

要设置一个进程的优先级,需要调用其setPriority方法:

public final void setPriority(int priority)

要点3:停止线程

Thread类有一个 stop 方法,用来停止一个线程,但是这种方法是不安全的,不推荐使用。
推荐的方法是使用带有一个条件的while循环,当想要停止线程的时候,直接让该条件计算为假即可。
例如:

boolean condition = true;   
public void run {
    while (condition) {
        // do something here  
    }
}

在你的类中,还需要提供一个方法来修改condition的值:

public synchronized void stopThread(){
    conditon = false;
}

要点4:同步

当多个线程需要同时访问相同的资源或数据时将会发生线程干扰问题。

原子操作

  • 原子操作是可以组合起来让系统的其他部分将其当作是一个单个的操作的一组操作。
  • 原子操作不会引发线程干扰。
  • 在Java中,除了long和double之外的所有基本类型,都是原子性的可读和可写的。

方法同步

  • 每个Java对象都有一个内在的锁,有时候叫作监控锁。获取一个对象的内在的锁,是一种独占式地访问一个对象的方法。试图访问一个锁定的对象的线程将会被阻塞,直到持有锁的线程释放该锁为止。
  • 锁提供了2个功能:互斥功能 和 可见性。
  • synchronized 修饰符可以用来锁定一个对象。
  • 锁是可以重用的,持有锁的线程可以在同一个对象上调用其他的同步的方法。
  • 在一个程序中,保证一次只有一个线程能够访问一个共享资源的代码段,就是所谓的关键代码段。

块同步

Java允许通过块同步来锁定任何的对象,语法如下:

synchronized(object){
    // do something while locking object
}

同步的块给了你一个对象的内在锁,在块的代码执行之后,释放该锁。

方法同步和锁定当前对象的块同步是一样的。

可见性

  • 如果追求可见性,而不需要互斥的话,可以使用 volatile 关键字而不是 synchronized 关键字,这样可以免去锁定一个对象带来的运行时的负担。
  • volatile 只能解决可见性问题,不能解决互斥问题。

要点5:线程协调

public final void wait() throws InterruptedException    

上面代码使当前线程等待,直至另一个线程调用notify或notifyAll方法,

public final void wait(long timeout) throws InterruptedException   

导致当前线程等待,直到另一个线程针对该对象调用notify或notifyAll方法,或者经过了指定的时间量。

public final void notify()

通知单个的线程,等待该对象的锁。如果有多个线程,随即选择其中之一来通知。

public final void notifyAll()   

通知所有的线程,等待该对象的锁。

第20章要点:

要点1:原子变量

java.util.concurrent.atomic包提供了诸如AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference等类。这些类可以执行各种原子性的操作。

要点2:Executor 和 ExecutorService

  • 尽可能不要使用java.lang.Thread来执行一个Runnable的任务。而是使用java.util.concurrent.Executor或者其子接口的实现。

  • 通过Executors提供四种线程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。

    • public static ExecutorService newFixedThreadPool(int nThreads) 

      创建固定数目线程的线程池。

    •   public static ExecutorService newCachedThreadPool() 

      创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

    •   public static ExecutorService newSingleThreadExecutor() 

      创建一个单线程化的Executor。

    •   public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 

      创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

要点3:Callable和Future

  • Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。

  • Callable接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法在线程池中执行Callable内的任务。由于Callable任务是并行的(并行就是整体看上去是并行的,其实在某个时间点只有一个线程在执行),我们必须等待它返回的结果。 java.util.concurrent.Future对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。

要点4:锁

  • synchronized 锁机制存在局限性,例如:一个线程试图获取无法回退的锁,并且如果没有获取这个锁的话,将无限地阻塞下去;没有办法在一个方法中锁定一个资源,而在另一个方法中释放它。
  • Lock类提供了克服Java的内建锁的局限性。Lock带有lock方法和unlock方法。只要保留了对锁的引用,可以在程序中的任何地方释放该锁。
  • 在lock调用之后的一个finally子句中调用unlock方法可以解决锁的释放问题。

第22章要点:

要点1:

教材学习中的问题和解决过程

  • 问题1:书上p199上“在Java中,除了long和double之外的所有的基本类型,都是原子性的可读和可写的。”为什么long和double类型的读写不是原子性的?
  • 问题1解决方案:通过代码实现了两个线程对同一个成员变量进行读写操作,来测试long和double类型变量的读写不是原子性操作。结果发现确实是原子性操作,与书上说的不符。又查找了资料,发现是由于书上说的情况是32位JVM,32位JVM对64位的数据的读、写分两步,每一步读或者写32位的数据,这样就会造成两个线程对同一个变量的读写出现一个线程写高32位、另一个线程写入低32位数据。这样此变量的数据就出现不一致的情况。而我实验用的是64位JVM,所以得到的结果是原子性的。

代码调试中的问题和解决过程

  • 问题1:将Thread优先级设为“20”报错。

  • 问题1解决方案:查看函数定义后发现,优先级设置的值不能超过MAX_PRIORITY(默认为10)。

代码托管

上周考试错题总结

  • 错题1
    Which of the following objects could contain the information “eastern standard time”?
    (Choose all that apply.)
    A .Instant
    B .LocalDate
    C .LocalDateTime
    D .LocalTime
    E .ZonedDateTime

    正确答案:E. ZoneDatedTime。只有ZoneDatedTime有涉及时区。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 300/500 1/3 17/37
第三周 787/1287 1/4 15/52
第四周 350/1637 1/5 16/68
第五周 1049/2686 1/6 20/88
  • 计划学习时间:20小时

  • 实际学习时间:20小时

参考资料

猜你喜欢

转载自www.cnblogs.com/PNIDEMOOO/p/10629659.html