Software Construction之Thread

 

Java中多线程的状态及转移

Thread.start()和Thread.run()的区别

  • Thread.start()只能被调用一次,而Thread.run()可以被调用多次
  • Thread.start()是真正的多线程,在得到cpu的time slice时,开始执行run()方法;而Thread.run()只是一个函数,当Thread.run()被调用时,程序顺序执行Thread.run()的内容,执行结束后才会继续执行后面的内容

    主动改变线程状态的方法

  • Thread.sleep()
    注意,Thread.sleep()需要处理InterruptedException异常
  • Thread.interrupt()
    注意,Thread.interrupted()只会在Thread.sleep()时或者使用Thread.interrupted()/Thread.currentThread().isInterrupted()时检测,否则即使外界调用Thread.interrupt(),线程仍然继续执行
    举例来说,下面的代码不会停止,会一直输出”Running”
    Thread a=new Thread(new Runnable() {
      @Override
      public void run() {
          while(true){
          System.out.println("Running");
          }
      }
    });
    a.start();
    a.interrupt();
    

    想要接收到interrupt信号需要下面这种写法

    Thread a=new Thread(new Runnable() {
      @Override
      public void run() {
          while(!Thread.interrupted()){
          System.out.println("Running");
          }
      }
    });
    a.start();
    a.interrupt();
    

    或者

    Thread a = new Thread(new Runnable() {
      @Override
      public void run() {
          try {
              while (true) {
                  System.out.println("Running");
                  Thread.sleep(100);
              }
          }
          catch (InterruptedException ie){
          }
      }
    });
    a.start();
    a.interrupt();
    

    Thread Safe

    Confinement

    线程之间不共享mutable数据(避免使用mutable的全局变量)

    Immutability

  • No mutator methods
  • All fields are private and final
  • No representation exposure
  • No mutation whatsoever of mutable objects in the rep not even beneficent mutation

    Threadsafe Data Types

    private static Map<Integer,Boolean> cache = Collections.synchronizedMap(new HashMap<>());
    

    即使在线程安全的ADT上,使用 iterator也是不安全的

    Lock

    使用synchronized 使用方法:

    public void foo(){
      synchronized(this){
          ...
      }
    }
    

    等价于

    public synchronized void foo(){
      ...
    }
    

    Threadsafe 和 race condition

    注意:这是两个没有关系的词
    Threadsafe只保证在多线程的情况下,ADT依然满足ADT的spec
    Threadsafe的ADT依然会发生race condition
    比如HashSet的Iterator,在多线程下不是ThreadSafe的,因为Iterator的spec要求在使用Iterator时,不能修改HashSet
    但即便使用了Collections.synchronizedMap,虽然get(),put()等操作是Threadsafe的,但Iterator仍然不是Threadsafe

    for (String s: lst) { ... } 
    // not threadsafe, even if lst is a synchronized list wrapper
    

    即使使用了Collections.synchronizedMap,当两个Thread同时调用put()操作,是race condition

    synchronized (list) { ... }
    只代表别人不能用list的锁

    死锁(Deadlock)

    如下图所示,当T1进入锁定a,T2进入锁定b后,T1和T2进入死锁

    如何判断死锁?
    两个进程有T1和T2,锁的序列为S1和S2,取S1和S2的任意两个前缀P1和P2(P1∩P2为空),以及相应的下一位N1和N2。
    若N1$\in$P2且N2$\in$P1则N1和N2死锁。