线程同步----synchronized

来源:互联网 发布:cfnet跟踪算法 编辑:程序博客网 时间:2024/05/16 06:45

一、在用多线程实现火车票系统时,当一个线程执行Thread.sleep(10);后,会有另一个线程进入到代码当中,这样就会不安全,所以在一个线程睡眠时为了防止另一个线程进入到该代码使用线程同步。

  1. 每一个对象都有一个监视器,或者叫做锁。
  2. 同步方法利用的是this所代表的对象的锁。
  3. 每个class也有一个锁,是这个class所对应的Class对象的锁。
二、实现同步的两种方式:
  1. 同步代码块,在需要同步的一段代码当中使用synchronized(任何对象)如:
  • Object obj = new Object();
  • synchronized(obj){    执行代码;    }
-----在一个线程进入执行代码段时,不允许别的线程进入,除非该线程执行完代码
  • synchronized(this){    执行代码;    }
-----如果同步方法和同步代码块需要保持一致,则两者都对this进行同步
  1. 同步方法,在需要同步的方法前使用synchronized关键字,如:
  • public synchronized void sell(){ 执行代码  }
-----同步方法对this进行加琐

注:线程的死锁:线程1锁住了对象A的监视器,等待对象B的监视器,线程2锁住了对象B的监视器,等待对象A的监视器,就造成了死锁。

三、wait()、notify()、notifyAll(),三个方法应在同步方法或同步块当中调用
  1. 每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,它的对待队列是空的。
  2. 我们应该在当前线程锁住对象的锁后,去调用该对象的wait方法。会产生异常。
  3. 当调用对象的notify方法时,将从该对象的等待队列中删除一个任意选择的线程,这个线程将再次成为可运行的线程。
  4. 当调用对象的notifyAll方法时,将从该对象的等待队列中删除所有等待的线程,这些线程将成为可运行的线程。

四、实例

  • class Try
  • {
  • public static void main(String [] args){
  • Queue q = new Queue();
  • Producer p = new Producer(q);
  • Consumer c = new Consumer(q);
  • p.start();
  • c.start();
  • }
  • }


  • class Producer extends Thread{
  • Queue q;
  • Producer(Queue q){
  • this.q = q;
  • }
  • public void run(){
  • for(int i=0;i<10;i++){
  • q.put(i);
  • System.out.println("Producer put:"+i);
  • }
  • }
  • }


  • class Consumer extends Thread{
  • Queue q;
  • Consumer(Queue q){
  • this.q = q;
  • }
  • public void run(){
  • while(true){
  • System.out.println("Consumer get:"+q.get());
  • }
  • }
  • }


  • class Queue{
  • int value;
  • boolean bFull = false;
  • public synchronized void put(int i){
  • if(!bFull){
  • value = i;
  • bFull = true;
  • notify();
  • }
  • try{
  • wait();
  • }catch(Exception ex){
  • ex.printStackTrace();
  • }
  • }
  • public synchronized int get(){
  • if(!bFull){
  • try{
  • wait();
  • }catch(Exception e){
  • e.printStackTrace();
  • }
  • }
  • bFull = false;
  • notify();
  • return value;
  • }
  • }