举个小栗子,重新理解一下synchronized,volatile,wait(),notify(),join()

 

直接步入正题:

1、若有一个方法需要实现多线程情况下一个一个访问,则可使用synchronized关键字来实现。

2、若有一个工作是需要用两个或多个线程来共同协作完成,并且必须是完成某个动作之后才能执行下一个动作,则可使用 wait() 和 notify() 结合来操作,也可使用volatile关键字来实现 ,也可以使用join()来实现。

举个栗子:

/**
 * @author HMM
 *
 */
public class TestWait {

	String name = "QQQ";//随意

	volatile boolean flag = false;// volatile 关键字使flag线程之间可见
	
	/**
	 * 使用synchronized来完成排队吃饭的动作
     * 一个一个排队吃饭饭呦
	 */
	public synchronized void eat() {
		System.out.println("当前线程ID:" + Thread.currentThread().getId() + ",在吃饭,等会吧");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("当前线程ID:" + Thread.currentThread().getId() + ",吃完了,下一位");
		System.out.println("===============================================\n");
	}

	/**
     * 方式1
	 * 使用wait 和 notify 来实现先下载图片再展示图片动作
	 */
	public void downAndShow() {
		// 开启一个线程专门下载图片
		new Thread(new Runnable() {
			public void run() {
				downLoad();
			}
		}).start();

		// 开启一个线程专门显示图片
		new Thread(new Runnable() {
			public void run() {
				show();
			}
		}).start();
	}

	public void downLoad() {
		System.out.println("开始下载图片");
		for (int i = 0; i < 101; i += 10) {
			System.out.println("down" + i + "%");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		synchronized (name) {
			name.notify();
		}
		System.out.println("图片下载成功");
	}

	public void show() {
		synchronized (name) {
			try {
				name.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("展示图片");
		}
	}
	
	
	/**
	 * 方式2
     * 使用 volatile 关键字
	 */
	public void volatileDownAndShow() {
		
		// 开启一个线程专门下载图片
		new Thread(new Runnable() {
			public void run() {
				volatileDownLoad();
			}
		}).start();
		
		// 开启一个线程专门显示图片
		new Thread(new Runnable() {
			public void run() {
				volatileShow();
			}
		}).start();
	}
	
	public void volatileDownLoad() {
		System.out.println("开始下载图片");
		for (int i = 0; i < 101; i += 10) {
			System.out.println("down" + i + "%");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		flag = true;//设置flag为true,表示我已经把图片下载好了,剩下的交给你了兄弟
		System.out.println("图片下载成功");
	}
	
	public void volatileShow() {
		while (true) {//死循环,模拟自旋锁
			if(flag){//因为flag 为volatile 所以在线程之间可见,线程1改变后,线程2也会随之改变
				System.out.println("展示图片");
				break;
			}
		}
	}

    /**
	 * 方式3
	 * join()
	 * @throws InterruptedException 
	 * 
	 */
	public void JoinDownAndShow() throws InterruptedException {
		
		// 开启一个线程专门下载图片
		Thread thread1 = new Thread(new Runnable() {
			public void run() {
				JoinDownLoad();
			}
		});
		
		// 开启一个线程专门显示图片
		Thread thread2 = new Thread(new Runnable() {
			public void run() {
				JoinShow();
			}
		});
		
		thread1.start();
		thread1.join();// thread1调用join()方法,等到thread1执行完毕之后才执行下面操作
		thread2.start();
	}
	
	public void JoinDownLoad() {
		System.out.println("join() 方式 开始下载图片");
		for (int i = 0; i < 101; i += 10) {
			System.out.println("down" + i + "%");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("图片下载成功");
	}
	
	public void JoinShow() {
		System.out.println("展示图片");
	}
}

编写测试类:

public class Test {

	public static void main(String[] args) {
		final TestWait tt = new TestWait();
		//开始10个线程来模拟排队吃饭
//		for(int i=0;i<10;i++){
//			new Thread(new Runnable() {
//				public void run() {
//					tt.eat();
//				}
//			}).start();;
//		}
		
//		tt.downAndShow();
//		tt.volatileDownAndShow();
		tt.JoinDownAndShow();
	}
}

结果展示:

1、排队吃饭示例:

2、wait() 和 notify() 实现下载图片后展示:

3、volatile方式实现下载图片后展示:

就酱。共勉

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值