今天复习了java中Thread类的使用,以及使用synchronized关键字对对象上锁。以及wait/notify进行线程间的同步。
 
实现自己的线程类有2种方法,一种是extends Thread类,然后重写run方法。
第二种是实现Runnable接口,并implements run方法。
 
Thread类中有一个成员叫做Target,是一个Runnable的引用。当我们使用无参数的构造方法时,这个target是赋成null的。如果使用一个实现Runnable的类的对象来new一个Thread,那么这个对象的引用就会传给target的,Thread的run方法就是调用这个target的run方法。
所以,如果使用继承Thread的方法来实现自己的线程类,那么就要重写run方法,否则它什么都不做,因为此时target是null。
 
 
Synchronized的关键字
可以作用于方法,也可以作用于代码块。
每个object都有一把锁,当有线程调用被synchronized修饰的非static方法时,该object会被上锁,直到调用结束,释放锁之后,其他线程才可调用该object中synchronized修饰的非static方法.
如果是static的方法被修饰,那么是对应的class类的对象被上锁,该对象唯一。
使用synchronized代码块的好处是,首先,更精确,仅把必要的代码列入临界区间。还有就是,可以为不同的代码块使用不同的锁。

点击(此处)折叠或打开

  1. Synchronized(mutex_1){

  2.     critical section_1

  3. }
  4. Synchronized(mutex_2){

  5.     critical section_2

  6. }

wait/notify
首先明确的一点是,这两个方法是Object提供的,而不是Thread类提供的。
最重要的一句话时,The current thread must own this object's monitor.
即当前线程必须是该对象monitor的持有者,换句话说,只要在synchronized修饰的方法或代码块中才能使用这两个方法,否则,会抛出IllegalMonitorStateException
 
举个例子

点击(此处)折叠或打开

  1. class Test{

  2.    private Object mutex = new Object();

  3.    public void Fun_1{
  4.         Synchronized(mutex){
  5.             while(some condition){
  6.                 mutex.wait();
  7.             }
  8.         }
  9.    }
  10. }
这里调用wait时,一定是mutex的,如果调用的是this的wait方法,那么就会出现异常,原因是当前线程没有持有this的锁。
 
 
做了个小练习,有一个栈,有生产者和消费者,生产者负责将26个英文字母依次push到栈中,消费者则进行pop操作。栈的大小是10.我假设一个生产者,2个消费者。
 

点击(此处)折叠或打开

  1. package threadCommunication2;

  2. public class Stack {
  3.     private final int MAX = 10;//栈的大小是10
  4.     private char[] buffer;//为了简单,我就用了个数组
  5.     private int top;//栈顶

  6.     public Stack() {
  7.         this.buffer = new char[MAX];
  8.         this.top = -1;
  9.     }

  10.     public void push(char c) {

  11.         synchronized (this) {
  12.             while (top == MAX-1) {//当栈满了时,要等消费者来唤醒

  13.                 System.out.println("buffer is full...");
  14.                 try {
  15.                     wait();
  16.                 } catch (InterruptedException e) {
  17.                     e.printStackTrace();
  18.                 }

  19.             }
  20.             buffer[++top] = c;

  21.             try {
  22.                 Thread.sleep((long) (Math.random() * 100));//随机延迟
  23.             } catch (InterruptedException e) {

  24.                 e.printStackTrace();
  25.             }
  26.             System.out.println(c + " is pushed");
  27.             notify();
  28.         }

  29.     }

  30.     public char pop() {

  31.         synchronized (this) {//栈空时,被wait阻塞,等待生产者唤醒
  32.             while (top == -1) {
  33.                 System.out.println("buffer is empty...");
  34.                 try {
  35.                     wait();
  36.                 } catch (InterruptedException e) {
  37.                     e.printStackTrace();
  38.                 }

  39.             }
  40.             char tmp = buffer[top];
  41.             top--;

  42.             try {
  43.                 Thread.sleep((long) (Math.random() * 1000));
  44.             } catch (InterruptedException e) {

  45.                 e.printStackTrace();
  46.             }
  47.             notify();
  48.             return tmp;
  49.         }

  50.     }

  51. }

 

点击(此处)折叠或打开



  1. package threadCommunication2;

  2. public class PushThread extends Thread {

  3.     private Stack s;

  4.     public PushThread(Stack s) {

  5.         this.s = s;

  6.     }
  7. public void run() {

  8.         int i = 'a';

  9.         while (i != 'z'+1) {

  10.             s.push((char) i++);
  11.         }
  12.     }
  13. }


点击(此处)折叠或打开

  1. package threadCommunication2;

  2. public class PopThread extends Thread {

  3.     private Stack s;

  4.     public PopThread(Stack s) {

  5.         this.s = s;

  6.     }

  7.     public void run() {

  8.         int i = 0;

  9.         while (i < 13) {
  10.             System.out.println(s.pop());
  11.             i++;
  12.         }

  13.     }

  14. }

这个pop比较囧。。。13是事先算的,一个消费者取出13个。。。因为主要是复习同步,所以这些暂且这么样吧。
 

点击(此处)折叠或打开

  1. package threadCommunication2;

  2. public class Main {
  3.     public static void main(String[] args) {

  4.         Stack stack = new Stack();

  5.         Thread push = new PushThread(stack);

  6.         Thread pop = new PopThread(stack);
  7.         Thread pop1 = new PopThread(stack);

  8.         push.start();
  9.         pop.start();
  10.         pop1.start();

  11.     }
  12. }
09-28 03:25