day23

文章目录

synchronized 关键字及线程同步

解决线程安全问题的二种方案:

使用同步代码块
使用步骤:
1.把访问了共享数据的代码块取出来,放到一个方法中
2.在方法上添加synchronized修饰符

   有时运行一些线程需要共享数据,例如两个线程同时存取一个数据流,其中一个对数据进行了修改,而另外一个线程使用的是原来的数据,这就带来了数据不一致的问题,如果多线程同时操作一个对象,则称该对象不是线程安全的。为了使多线程机制能够正常运转,需要采取一些措施来防止两个线程访问相同资源的冲突。特别是在关键的时期,为了防止出现这样的冲突,需要在线程使用一个资源时为其加锁。访问资源的第一个线程加上锁以后,其他线程就不能再使用这个资源了除非第一个线程被解锁。
    对一种特殊的资源,Java提供了内建的机制来防止它们的冲突。这种机制就是对相关的方法使用关键字synchronized
   为了协调和同步线程对共享数据的操作,java.lang.Obiect类中提供了wait()方法和notify()方法实现线程的同步。这两个方法始终在循环中使用:不带参数的wait()方法一直等待,单位为毫秒,到达参数指定的时间后,线程又成为就绪状态;如果没有到达指定的时

间,则需要其他线程调用notify()方法将其唤醒。
使用wait()方法和notify()方法,同时配合条件检查可以有效控制多线程之间的运行
顺序,实现多线程之间的同步。

解决线程安全问题的二种方案:使用lock锁

使用步骤:

  1. void lock()获取锁
  2. void unlock()释放锁

代码及运行结果

package demo01;

public class Demo01Ticket {
	public static void main(String[] args) {
		RunnableImpl run =new RunnableImpl();
		Thread t0=new Thread(run);
		Thread t1=new Thread(run);
		Thread t2=new Thread(run);
		t0.start();
		t1.start();
		t2.start();
	}

}
package demo01;
/*
 * 解决线程安全问题的二种方案:使用同步代码块
 * 使用步骤:
 * 1.把访问了共享数据的代码块取出来,放到一个方法中
 * 2.在方法上添加synchronized修饰符
 * */
public class RunnableImpl implements Runnable {
	private int ticket =100;
	@Override
	public void run() {
		while(true) {
			while(true) {
				payTicket();}
		}
	}
		public synchronized void payTicket() {
			if(ticket>0) {
				try {
					Thread.sleep(10);
				}catch(InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
				ticket--;
			}
			
		
	}

}
package demo02;

public class Demo02Ticket {
	public static void main(String[] args) {
		RunnableImpl run =new RunnableImpl();
		Thread t0=new Thread(run);
		Thread t1=new Thread(run);
		Thread t2=new Thread(run);
		t0.start();
		t1.start();
		t2.start();
	}

}

day23

package demo02;

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

/*
 * 解决线程安全问题的二种方案:使用lock锁
 * 使用步骤:
 * 1. void lock()获取锁
 * 2. void unlock()释放锁 
 * 
 * */
public class RunnableImpl implements Runnable {
	private int ticket =100;
	//1.在成员位置创建一个ReentrantLock对象
	Lock l=new ReentrantLock();
	@Override
	public void run() {
		while(true) {
			//2.在可能会出现线程安全的地方,调用Lock接口中的lock方法,获取锁
			l.lock();
			if(ticket>0) {
				try {
					Thread.sleep(10);
					System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
					ticket--;
				}catch(InterruptedException e) {
					e.printStackTrace();
				}finally {
					//3.在可能会出现线程安全的地方,调用unLock 释放锁
				l.unlock();
			}
			}
		}
	}
		
	}

day23

package demo03;
/*
 * 等待唤醒案例:
 * 创建一个顾客线程,告知老板要的包子种类,用wait()方法等待,放弃cpu执行
 * 创建一个老板线程,花五秒做一个包子,做好之后,用notif通知顾客吃包子
 * 
 * */
public class WaitAndNotify{
	public static void main(String[] args) {
	Object obj=new Object();
	//创建第一个消费者
	new Thread() {
		@Override
		public void run() {
			while(true) {
				synchronized(obj){
					System.out.println("消费者1,告知老板包子要的种类");
					try {
						obj.wait();
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("消费者1,包子已经做好了,开吃");
					System.out.println("=========");
				}
				}
		}
	}.start();
	new Thread() {
         @Override
		public void run() {
			while(true) {
				synchronized(obj){
					System.out.println("消费者2,告知老板包子要的种类");
					try {
						Thread.sleep(2000);
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("消费者2,包子已经做好了,开吃");
					System.out.println("=========");
					
			}
         }
         }
	}.start();}
}

day23

大数据200周敏2020080605048

上一篇:每日一题 | day23(微信红包 | 计算字符串的距离)


下一篇:微服务架构Day23-SpringCloud之网关