java多线程(二)--多个线程访问共享对象和数据的方式

线程的相关概念:

  • 多线程:是指在一个程序(进程)中,运行时产生了不止一个线程。
  • 并行:是指多个cpu实例或者多台机器同时进行一段逻辑处理,是同时运行。
  • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时进行。并发往往在场景中有公共的资源,那么针对这个资源的调用会产生一个瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。(TPS/QPS:每秒钟Request/事务的 数量)。
  • 线程安全:经常用来描述一段逻辑处理的代码。指在并发的情况下,该代码经过多线程使用,线程的调用顺序不影响任何结果。如不加事务处理的转账逻辑。
  • 线程同步:保证共享资源的多线程访问成为线程安全,来保证结果的准确行。如在多个线程调用的方法上加入synchronization关键字处理,在保证结果的同时,提高性能才是一个优秀的程序。在程序线程安全和程序性能的优先级上,线程安全较大。

 

一、如果每个线程的执行代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据。

例子:售票。

public class ThreadShareBuyTicketDemo {
	public static void main(String[] args) {
		BuyTicket buyTicket = new BuyTicket();
		new Thread(buyTicket,"窗口一").start();
		new Thread(buyTicket,"窗口二").start();
	}
}
class BuyTicket implements Runnable{
	private int count = 100;

	@Override
	public void run() {
		while(true){
			synchronized (this) {
				if(count > 0 ){
					try {
						Thread.sleep(100);
						count--;
						System.out.println(Thread.currentThread().getName()+"余票数:"+count);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}else{
				}
			}
		}
	};
	
}
//加锁的写法
public class SalTickets {
	public static void main(String[] args) {
		/**
		 * 如果每个线程的执行代码相同,那么可以共用一个Runnable对象,这个Runnable有那个共享数据
		 */
		Tickets tickets = new Tickets();
		new Thread(tickets,"窗口一").start();
		new Thread(tickets,"窗口二").start();
	}
}

class Tickets implements Runnable{
	Lock lock = new ReentrantLock();
	private int tickeCount = 100;
	
	@Override
	public void run() {
		while(true){
			sals();
		}
	}
	public void sals(){
		lock.lock();
		try {
			Thread.sleep(100);
			if(tickeCount > 0){
				tickeCount --;
				System.out.println("窗口"+Thread.currentThread().getName()+"还剩票数:"+ tickeCount );
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
}

二、如果每个线程执行代码不同,这时候需要不同的Runnable对象(把对线传到Runnable中)。

例子一:设计4个线程,其中两个线程每次对j+1,另外两个线程每次对j-1。

public class ThreadMultiShareDemo {
	
	public static void main(String[] args) {
		final ThreadMulti threadMulti = new ThreadMulti();
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<100;i++){
						threadMulti.increment();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<100;i++){
						threadMulti.decrement();
					}
			}
		}).start();
	}
	
}
class ThreadMulti{
	private int j=10;
	
	public synchronized void increment(){
		j++;
		System.out.println("j++ 了:"+j);
	}
	
	public synchronized  void decrement(){
		j--;
		System.out.println("j-- 了:"+j);
	}
}

注:这里increment方法和decrement方法加synchronized关键字是因为当两个线程同时操作同一个变量时,就算是简单的j++操作时,在系统底层也是通过多条机器语句来实现,所以在执行j++过程也是要耗费时间,这时就有可能在执行j++的时候,另外一个线程H就会对j进行操作,因此另外一个线程H可能操作的可能就不是最新的值了。因此要提供线程同步。

例子二:消费者和生产者模式

一个生产者::一个消费者

public class ProductAndCustomer {
	public static void main(String[] args) {
		UserAction action = new UserAction();
		new Thread(new product(action)).start();
		new Thread(new product(action)).start();
	}
	
	static class product implements Runnable{
		public UserAction action;
		public product(UserAction action){
			this.action = action;
		}
		
		@Override
		public void run() {
			while(true){
					action.productAction(10);
			}
		}
		
	}
	static class customer implements Runnable{
		public UserAction action;
		public customer(UserAction action){
			this.action = action;
		}
		
		@Override
		public void run() {
			while(true){
					action.customerAction(10);
			}
		}
		
	}
}
class UserAction{
	//现有商品
	private int currentGoods = 0;
	//最大库存
	private int maxInventory = 30;
	//消费
	public synchronized void customerAction(int num){
		try {
			if(num>currentGoods){
				System.out.println("通知消费者:"+Thread.currentThread().getName()+",现有库存不足,正在生产中");
					this.wait();
			}
			currentGoods -= num;
			System.out.println("用户:"+Thread.currentThread().getName()+"消费了商品:"+num+",库存还有:"+currentGoods);
			this.notify();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	//生产
	public synchronized void productAction(int num){
		try {
			if((num+currentGoods) > maxInventory){
				currentGoods = 30;
				System.out.println("通知生产者:"+Thread.currentThread().getName()+"库存已满,库存还有:"+currentGoods);
				this.wait();
			}
			currentGoods += num;
			System.out.println("生产者:"+Thread.currentThread().getName()+"生产了商品:"+num+",库存还有:"+currentGoods);
			this.notify();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 多个生产者::多个消费者。当有多个生产者和多个消费者的时候,运行的结果会出现负值,这意味着,我们线程出现了不同步,这个时候我们需要吧if判断改为while,和this.nitifyAll();

原因是要线程wait();的时候,需要while来保证线程可运行,一旦线程被唤醒,直接运行。

package com.XC.saleticket;

public class ProductAndCustomer {
	public static void main(String[] args) {
		UserAction action = new UserAction();
		new Thread(new product(action)).start();
        new Thread(new product(action)).start();
		new Thread(new customer(action)).start();
        new Thread(new customer(action)).start();
	}
	
	static class product implements Runnable{
		public UserAction action;
		public product(UserAction action){
			this.action = action;
		}
		
		@Override
		public void run() {
			while(true){
					action.productAction(10);
			}
		}
		
	}
	static class customer implements Runnable{
		public UserAction action;
		public customer(UserAction action){
			this.action = action;
		}
		
		@Override
		public void run() {
			while(true){
					action.customerAction(10);
			}
		}
		
	}
}
class UserAction{
	//现有商品
	private int currentGoods = 0;
	//最大库存
	private int maxInventory = 30;
	//消费
	public synchronized void customerAction(int num){
		try {
			while(num>currentGoods){
				System.out.println("通知消费者:"+Thread.currentThread().getName()+",现有库存不足,正在生产中");
					this.wait();
			}
			currentGoods -= num;
			System.out.println("用户:"+Thread.currentThread().getName()+"消费了商品:"+num+",库存还有:"+currentGoods);
			this.notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	//生产
	public synchronized void productAction(int num){
		try {
			while((num+currentGoods) > maxInventory){
				currentGoods = 30;
				System.out.println("通知生产者:"+Thread.currentThread().getName()+"库存已满,库存还有:"+currentGoods);
				this.wait();
			}
			currentGoods += num;
			System.out.println("生产者:"+Thread.currentThread().getName()+"生产了商品:"+num+",库存还有:"+currentGoods);
			this.notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

总结:在多线程中尽量使用while语句,当使用Lock的时候,lock.unlock();一定要写在finally里面。this.wait();this.notify();this.notifyAll();要写在synchronized里面。

资料:https://www.cnblogs.com/wxd0108/p/5479442.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值