Java MultiThread学习笔记

1. synchronized function

用法:  synchronized foo() {}


字面意思是让一个函数块保持同步,但是保持和谁同步呢? 答案是和另一个或一些加了synchronized 关键字的函数,它能保证在这个对象内,所有加synchronized 的函数在同一时间只有一个在运行,并只运行在某一个线程中,假如这些函数可能会被运行在不同的线程,又要同时访问同一个资源,那么就可以用它了。 (这段话不知道我说对了没有)Only one thread at a time can call a synchronized method for a particular object (although that thread can call more than one of the object’s synchronized methods). Objects can have synchronized methods that prevent threads from accessing that object until the synchronization lock is released。


例如 :

synchronized foo0() { A;}

synchronized foo1() { B;}


A, B 之间如果想同步,(即A执行时B不能执行,B执行时A不能执行),需要把两个函数都加上synchronized,只加一个相当于没加。

If you synchronize only one of the methods, then the other is free to ignore the object lock and can be called with impunity. This is an important point: Every method that accesses a critical shared resource must be synchronized or it won’t work right. 


2. synchronized object 

用法:
synchronized(syncObject) {
  // This code can be accessed 
  // by only one thread at a time
}

字面意思是同步一个对象,实际上是用一个对象当作锁,来创建一个临界区(Critical section),临界区内代码同一时间只能由一个线程来访问,进一步说,syncObject只有一把钥匙,在一个时间点上,哪个线程拿到这把钥匙,哪个线程就可以进入临界区,执行完后返回钥匙给syncObject,其它没钥匙的线程等钥匙空闲了之后,再由系统决定把钥匙给谁。

注意:synchronized 方法滥用会降低系统性能,因为进入、退出同步方法(块)时会多一些操作,尽量少用。

另外, 在非同步线程中访问另一个线程的ArrayList,应该克隆一份:
    ArrayList lv = null;
    // Make a shallow copy of the List in case 
    // someone adds a listener while we're 
    // calling listeners:
    synchronized(this) {
      lv = (ArrayList)actionListeners.clone();
    }

其中,synchronized(this) {}相当于synchronized foo() {}的效果,即用当前对象的大锁来同步。
PS synchronized  不会被子类继承。

线程基本知识:
线程的四种状态:
1 新的
2 可运行的 Runnable 随时可能被运行,有时运行,有时不运行
3 死的 Dead 通常发生在run{}退出后
4 阻塞的 Blocked

3 How to BLOCK a Thread? 
多线程的重点是如何去阻塞一个线程?目的是利用阻塞来实现某种程度的同步。阻塞有两种:Sleep和 wait/notify。
区别:Sleep不释放当前线程对象的锁,而wait释放当前线程的锁,由notify来重新拿回锁,拿回锁之后,执行wait()之后的程序。
使用wait/notify的注意事项:
因为这两个函数要操作当前对象的锁,不能做“无米之炊”,操作锁之前要拿到这把锁,然而什么时机才能确保我们手中有锁呢?
答案是在synchronized 同步块(方法)中,其中同步块即synchronized(Object o){},可以确保拿到Object的锁, 而同步方法即  synchronized void foo() {}, 可以确保拿到些函数所处对象的锁,总结以上的经验, 应该这样来调用wait()/notify():

synchronized (object) {
   ...
   try {
     object.wait();
   } catch(InterruptedException e) {
   }
   //object.notify();
   ...
}

synchronized void foo () {
   ...
   try {
      wait(); //Current thread wait();
   } catch(InterruptedException e) {
   }
   //object.notify();
   ...
}

注意catch线程中断的异常。

4 死锁
当一个线程A 因为另一个线程B而阻塞,而线程B因为线程C阻塞,C又因为A阻塞,这样的无限循环造成死锁。写程序的时候一定要小心,因为一旦出现死锁,你将会“死”很久去调试。

5 退出线程的方法
5.1 Use stop mark:
  public void terminate() { stop = true; }
  public void run() {
    while (!stop) {
    ......
    }
}


5.2    interrupt():

// blocked is a thread
if(blocked == null) return;
          Thread remove = blocked;
          blocked = null; // to release it
          remove.interrupt();

Note:开太多的线程可能会导致JVM停滞,能用线性的地方就不用多线程,线性过程比多线程快!线程一般用于提高用户响应速度,网络下载等。

你可能感兴趣的:(Java MultiThread学习笔记)