使用锁实现同步简单使用

如果想要static方法和普通的方法在同步情况下不能同时执行,单靠synchronized实现非常有难度,因为静态方法以class对象为锁,普通方法以具体的具体的对象为锁,java提供的另一种同步机制利用Lock接口及其实现类,比synchronized更加灵活。
synchronized可以支持更灵活的同步代码块结构,synchronized只能在synchronized块结构中获取和释放锁,Lock的方式更加灵活,可以不出现在同一个块结构中。
Lock方式提供了更丰富的功能,lock方式允许读写分离,性能更好,具有tryLock方法。
java并发包下三个重要的类Condition、ReentrantLock、ReentrantReadWriteLock是Lock的主要实现方式。
使用锁实现同步简单使用
实现了Lock接口:
使用锁实现同步简单使用
利用lock方式实现同步:

package com.sync.demo;

import java.io.Serializable;
import java.util.concurrent.locks.ReentrantLock;

public class Demo9 {
	private static ReentrantLock lock = new ReentrantLock();
	public static void main(String[] args) {
		long number = 100;
		
		NumberData numberData = new NumberData(number);
		Thread thread1 = new Thread(new User(numberData, 10));
		Thread thread2 = new Thread(new User(numberData, -50));
		Thread thread3 = new Thread(new User(numberData, 10));
		Thread thread4 = new Thread(new User(numberData, -10));
		Thread thread5 = new Thread(new User(numberData, -40));
		Thread thread6 = new Thread(new User(numberData, 10));
		Thread thread7 = new Thread(new User(numberData, -10));
		Thread thread8 = new Thread() {
			@Override
			public void run() {
				NumberData.staticFun1();
			}
		};
		
		Thread thread9 = new Thread() {
			@Override
			public void run() {
				NumberData.staticFun2();
			}
		};
		
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		thread6.start();
		thread7.start();
		
		thread8.start();
		thread9.start();
	}
	
	
	static class NumberData implements Serializable{
	
		private long number;

		public NumberData(long number) {
			this.number = number;
		}

		public long getNumber() {
			return number;
		}

		public void setNumber(long number) {
			this.number = number;
		}
		
		
		public  void add(long num) {
			lock.lock();
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				number = number + num;
				System.out.println("=======add============    "+num+"  "+number);
			
			lock.unlock();
		}
		
		public void del(long num) {
			lock.lock();
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				number = number + num;
				System.out.println("=======del============    "+num+"  "+number);
			lock.unlock();
			
		}
		
		public static void staticFun1() {
			lock.lock();
			for(int i=0;i<4;i++) {
				try {
					Thread.sleep(500);
					System.out.println("========staticFun1========");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			lock.unlock();
		}
		
         public static void staticFun2() {
        	 lock.lock();
        	 for(int i=0;i<4;i++) {
 				try {
 					Thread.sleep(500);
 					System.out.println("========staticFun2========");
 				} catch (InterruptedException e) {
 					e.printStackTrace();
 				}
 			}
        	 lock.unlock();
		}
	}
	
	static class User implements Runnable{

		private NumberData numberData;
		private long number;
		
		
		
		public long getNumber() {
			return number;
		}

		public void setNumber(long number) {
			this.number = number;
		}

		public NumberData getNumberData() {
			return numberData;
		}

		public void setNumberData(NumberData numberData) {
			this.numberData = numberData;
		}

		
		public User(NumberData numberData,long num) {
			super();
			this.numberData = numberData;
			this.number = num;
		}

		@Override
		public void run() {
			if (number > 0) {
				numberData.add(number);
			}else {
				numberData.del(number);
			}
		}
		
	}

}

result:

=======del============    -50  50
=======add============    10  60
=======add============    10  70
=======del============    -10  60
=======del============    -40  20
=======add============    10  30
=======del============    -10  20
========staticFun1========
========staticFun1========
========staticFun1========
========staticFun1========
========staticFun2========
========staticFun2========
========staticFun2========
========staticFun2========

2 Condition

在lock中利用Condition,一个锁可以关联一个或多个条件,使运行线程获取锁并且查看等待某一个条件是否满足,如果不满足则挂起直到某个线程唤醒它们。condition提供的挂起线程和唤起线程的机制,和object的wait,notify功能类似,Condition用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。Condition由Lock的newCondition()方法生成,condition的使用必须在lock和unLock之间,如果条件未满足需要在while循环中判断。lock 必须在 finally 块中释放。await()释放锁,然后挂起线程,其实是把线程放入了Condition引用的等待队列中。

signal作用类似notify,但大家都知道同时只有一个线程能够获取锁,其他线程仍要等待。其实signal()方法只是将Condition等待队列头结点移出队列,此时该线程节点还是阻塞的,同时将该节点的线程重新包装加入AQS等待队列(调用Lock.lock时会被加入AQS队列,调用await时会从AQS中移除,加入到Condition的等待队列),当调用unlock方法时会唤醒AQS等待队列中的节点,如果唤醒的节点不是刚刚移出的节点,那么刚刚移出Condition等待队列的节点还将继续被阻塞,否则节点会被唤醒。

Condition自己维护了一个等待信号的队列,并在适时的时候将结点加入到AQS的等待队列中来实现的唤醒操作。

具体Condition的原理会以后分析。

Condition可以为多个线程间建立不同的Condition, 利用使用lock/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。

Condition实现生产者消费者模式

package com.sync.demo;

import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo11 {
	 
    private int queueSize = 10 ;//最大仓库容量
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
 
    private Lock lock = new ReentrantLock();
    private Condition fullCondition = lock.newCondition();
    private Condition emptyCondition = lock.newCondition();
 
    class Consumer implements Runnable{
 
        @Override
        public void run() {
            consume();
        }
    
        //condition 必须在lock的保护之下
        private void consume() {
            while(true){
                lock.lock();
                try {
                	//循环中判断
                    while(queue.size() == 0){
                        try {
                            System.out.println("===========产品为空无法消费================");
                            emptyCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.poll();
                    //通知可以生产了(如果被阻塞挂起的话)
                    fullCondition.signal();
                    System.out.println("==============消费一个剩余==========="+queue.size());
                } finally{
                    lock.unlock();
                }
            }
 
        }
    }
   
    class Producer implements Runnable{
 
        @Override
        public void run() {
            produce();
        }
 
        private void produce() {
            while(true){
                lock.lock();
                try {
                    while(queue.size()== queueSize){
                        try {
                            System.out.println("================商品已经满仓了,不能生产=============");
                            fullCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //生产一个
                    queue.offer(1);
                    System.out.println("==============生产一个剩余==========="+queue.size());
                    //通知不为空了
                    emptyCondition.signal();
                } finally{
                    lock.unlock();
                }
            }
        }
 
    }
     
    public static void main(String[] args) {
    	Demo11 demo = new Demo11();
        Consumer cus = demo.new Consumer();
        Producer pro = demo.new Producer();
        Producer pro2 = demo.new Producer();
        Thread thread1 = new Thread(cus);
        Thread thread2 = new Thread(pro);
         
        thread1.start();
        thread2.start();
    }
}

上一篇:java condition 实现简单的阻塞队列


下一篇:Java并发系列(12)详解Condition的await和signal等待通知机制