学习笔记:synchronized中wait/notify,notifyAll用法与注意事项,以及自定义Lock锁

synchronized这是一个用于线程同步的关键字,提供了一种锁的机制,能够确保共享变量的互斥访问,防止数据不一致问题。主要修饰方法或者代码块,修饰方法时如果修饰静态方法则获得当前class对象的锁,修饰动态方法则获取当前对象实例锁,修饰代码块时获得的是指定对象锁,使用在对象的具体方法如下:

class Test{

   final Object syn;

    public static synchronized  void userFun(){  //获取的是class对象锁

      System.out.println("hello1");
  }

public synchronized void useBlock(){    

 
       System.out.println("hello2");
   

  }

public void useBlockWithObj(){  

    synchronized(syn){  //获取的是syn对象锁
    
       System.out.println("hello3");
    }

  }
}

在Object的源码中,jdk提供了几个在多线程环境下使用的方法,这些主要的方法有

wait():对当前对象持有的锁进行释放,并进入等待状态,除非调用notify或者被中断发生异常,否则该线程会一直处于阻塞状态

wait(long timeout):等待timeout时间后自动唤醒进程并继续执行。

notify():唤醒一个正在等待中的线程,并继续执行,如果有多个等待线程将由操作系统决定唤醒哪个

notifyAll():唤醒正在等待的所有线程,并继续执行,并交给操作系统处理

举个例子:

wait/noitify

public static void main(String[] arg) throws InterruptedException {
		//final BooleanLock block=new BooleanLock();
       final Object monitor=new Object();

		 new Thread(){
			 @Override
			 public void run() {
				 synchronized (monitor){


					 try {
						 monitor.wait();
						 System.out.println("thread1被唤醒");
					 } catch (InterruptedException e) {
						 e.printStackTrace();
					 }
					 for(int i=0;i<10;i++){
						 System.out.println("thread1-"+i);
					 }
					 monitor.notify();
				 }

			 }
		 }.start();
		new Thread(){
			@Override
			public void run() {

				synchronized (monitor){
					try {
						monitor.wait();
						System.out.println("thread2被唤醒");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					for(int i=0;i<10;i++){
						System.out.println("thread2-"+i);
					}
					monitor.notify();
				}

			}
		}.start();
		new Thread(){
			@Override
			public void run() {

				synchronized (monitor){
					try {
						monitor.wait();
						System.out.println("thread3被唤醒");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					for(int i=0;i<10;i++){
						System.out.println("thread3-"+i);
					}
					monitor.notify();
				}

			}
		}.start();
		new Thread(){
			@Override
			public void run() {

				synchronized (monitor){
					try {
						monitor.wait(1);
						System.out.println("thread4被唤醒");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					for(int i=0;i<10;i++){
						System.out.println("thread4-"+i);
					}
				}

			}
		}.start();
		TimeUnit.SECONDS.sleep(3);
		System.out.println("开始唤醒线程");
		synchronized (monitor){
			monitor.notify();
		}

	}

输出结果如下

thread4被唤醒
thread4-0
thread4-1
thread4-2
thread4-3
thread4-4
thread4-5
thread4-6
thread4-7
thread4-8
thread4-9
开始唤醒线程
thread1被唤醒
thread1-0
thread1-1
thread1-2
thread1-3
thread1-4
thread1-5
thread1-6
thread1-7
thread1-8
thread1-9
thread2被唤醒
thread2-0
thread2-1
thread2-2
thread2-3
thread2-4
thread2-5
thread2-6
thread2-7
thread2-8
thread2-9
thread3被唤醒
thread3-0
thread3-1
thread3-2
thread3-3
thread3-4
thread3-5
thread3-6
thread3-7
thread3-8
thread3-9

注意:当前几个方法需要在同步块中并且需要持有当前对象锁才能够调用成功,如果不是则会抛出IllegalMonitorStateExeption 异常

下面我们通过以上学习到的几个方法来设计一个显式锁

public class BooleanLock implements Lock {

	 private Object monitor;

	 public Thread currentThread;

	 public  List<Thread> list;

	 public boolean lock;


	 public BooleanLock(){
		 monitor=new Object();
		 list=new ArrayList<>();
	 }



	@Override
	public void lock() {
		lock("");
	}


	public void lock(Long mill) throws TimeoutException {
		synchronized (monitor){
			Thread tempThread=Thread.currentThread();

				try {
					Long resMill=mill;
					Long endMill=System.currentTimeMillis()+resMill;
					while(lock){
						if(!list.contains(tempThread)){
							list.add(tempThread);
						}
						monitor.wait(mill);
						resMill=endMill-System.currentTimeMillis();
						if(resMill<0){
							throw new TimeoutException();
						}

					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			list.remove(tempThread);
			lock=true;
			currentThread=tempThread;

		}
	}


	public void lock(String threadName) {
	 	 synchronized (monitor){
			 Thread tempThread=Thread.currentThread();

				try {
					while(lock){
						if(!list.contains(tempThread)){
							list.add(tempThread);
						}
						System.out.println(threadName+":锁被阻塞");
						monitor.wait();
						System.out.println(threadName+":锁被唤醒");
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			 list.remove(tempThread);
			lock=true;
			currentThread=tempThread;

		 }
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {

	}

	@Override
	public boolean tryLock(){
		lock=true;
		return true;
	}

	@Override
	public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
		return false;
	}

	@Override
	public void unlock() {
		synchronized (monitor){
			if(this.currentThread==Thread.currentThread()){
				lock=false;

				try {
					TimeUnit.MILLISECONDS.sleep(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("开始解锁");
				monitor.notifyAll();
			}
		}
	}

	@NotNull
	@Override
	public Condition newCondition() {
		return null;
	}
}
public static void main(String[] arg){
		final BooleanLock block=new BooleanLock();


		 new Thread(){
			 @Override
			 public void run() {
				 block.lock("Thread1");
					 for(int i=0;i<10;i++){
						 System.out.println("thread1-"+i);
					 }
				 block.unlock();
			 }
		 }.start();
		new Thread(){
			@Override
			public void run() {
				block.lock("Thread2");
				for(int i=0;i<10;i++){
					System.out.println("thread2-"+i);
				}
				block.unlock();
			}
		}.start();
		new Thread(){
			@Override
			public void run() {
				block.lock("Thread3");
				for(int i=0;i<10;i++){
					System.out.println("thread3-"+i);
				}
				block.unlock();
			}
		}.start();

	}

输出结果

Thread2:锁被阻塞
thread1-0
thread1-1
thread1-2
thread1-3
thread1-4
thread1-5
thread1-6
thread1-7
thread1-8
thread1-9
Thread3:锁被阻塞
开始解锁
Thread3:锁被唤醒
Thread2:锁被唤醒
Thread2:锁被阻塞
thread3-0
thread3-1
thread3-2
thread3-3
thread3-4
thread3-5
thread3-6
thread3-7
thread3-8
thread3-9
开始解锁
Thread2:锁被唤醒
thread2-0
thread2-1
thread2-2
thread2-3
thread2-4
thread2-5
thread2-6
thread2-7
thread2-8
thread2-9
开始解锁

 


 

 

上一篇:关于synchronized、wait、notify已经notifyAll的使用


下一篇:006 Java并发编程wait、notify、notifyAll和Condition