天天看点

软件构造试验的所学所感(4)--- 多线程编程线程的创建

在进行Lab6的编程之前,我先大概的了解了一下多线程编程里需要注意的问题和基本概念,本章我会介绍一些基本概念和我在做Lab6—猴子过河模拟器的时候遇到的问题和采用的方法,其中还有一些注意、提醒。

实验中基本不会用到一些比较复杂的多线程编程技巧,但是如果要学习Java肯定是要掌握这些的,但这里就不赘述了。仅仅谈论一些会用到的线程基础知识等

线程的创建

基本线程类指的Thread类,Runnable接口,Callable接口。目前而言我只看到过使用Runnable接口比较多,Thread类也有一些。

  • Thread 类实现了Runnable接口,启动一个线程的方法
MyThread my = new MyThread(); //MyThread是一个继承了Thread类的自定义类
       my.start();
           
  • 我使用的Runnable接口,因为接口比较灵活,我令Monkey类实现了该接口并且重写一个方法,如下:
public class Monkey implements Runnable{
 xxxxxxxx
 @Override
	public void run() {
	  xxxxxxx
	}
 xxxxxx
}
           

其中run方法里的东西就是猴子线程要执行的整个任务,因为猴子要过河,所以我这里就是猴子过河的整个过程。

要让线程启动,我使用的方法是匿名类(据说lambda表达式很简单)让线程启动的。如下:

new Thread(myMonkey).start();
           

同步锁部分

内部锁和条件存在一些局限,包括:

  • 不能中断一个正在试图获得锁的线程
  • 试图获得锁时不能设定超时
  • 每个锁仅有单一的条件,可能是不够的。

代码中最好既不使用Lock/Condition也不使用synchronized关键字,而是用阻塞队列。

但是如果实在不行就用synchronized,只有在特别需要Lock/Condition结构提供的独有特性的时候才使用Lock/Condition。

volatile域

volatile域为实例域的同步访问提供了一种免锁机制,它的值被一个线程设置但是却被另一个线程查询的时候可以使用这个。

书中介绍到:

除非使用锁或者volatile修饰符,否则无法从多个线程安全地读取一个域,当然final修饰的变量除外(仅考虑读取,如果有写入要考虑同步)

如果对共享变量除了赋值之外并不完成其他操作,那么可以将这些共享变量声明为volatile。

  • 最后说一些编写代码时候的一些想法:

我把猴子过河的整个过程利用sleep方法,使其在进行完自己的步骤之后sleep一定时间同时要把锁交出去,将控制权转让给别人。然后将一个时间段分割成好几个时间段,第一个时间段是猴子们整体过河,第二个时间段是输入日志,GUI的repaint,第三个时间段是清除上一个时间段猴子留下的影子(这个是为了防止猴子上帝视角了)

这种方法编写起来的确很轻松,但是需要时刻注意,如果占用锁的时候并行就变成了串行,如果其中有一个占用时长的操作,连起来会导致许多等待锁的进程还没有开始,就到了下一个时间段,因此如果这样做的话,一定要考虑好自己的操作里没有长的离谱的那种(比如有:文件写入(写入同一个文件))

继续阅读