JAVA多线程不安全问题解决方案(多线程并发同一资源)。

引例:吃苹果比赛,3个人同时吃50个苹果,谁先拿到谁就吃,每个哦ing过都有编号。

问题:

多线程同时执行的时候可能出现不安全问题
当3个人同时拿到一个苹果,他们的编号就一样,当时主要看是谁先吃掉苹果
除非拿到苹果和吃掉苹果是连续同步执行,没有其他的线程干扰

方案一:

设置同步代码块(同步锁)。

synchronized(共享资源){

同步执行代码;

}

class Apple implements Runnable{
	private int num=50;
	
	public void run() {
		for(int i=0;i<50;i++){
			synchronized (this) {//!!!解决了不安全问题,这里的this表示Apple共同资源
				//同步代码块
				//——————————————————————————————————————————————
				if(num>0){
				try {
					//导致一个资源信息被多个用户同时拿到
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"吃了编号为"+num+"的苹果");
				num--;
				//——————————————————————————————————————————————————
				}
			}
		}
	}
}
//Thread.currentThread().getName() 拿到当前线程的引用和名称

public class ImplementDemo {
	public static void main(String[] args) {
		Apple a=new Apple();
		new Thread(a,"A").start();
		new Thread(a,"B").start();
		new Thread(a,"C").start();
	}
}

方法二:

同步方法。

synchronized 方法名{

方法体(同步代码);

}

class Apple implements Runnable{
	private int num=50;
	
	public void run() {
		for(int i=0;i<50;i++){
		eat();
		}		
	}
	//——————————————————————————
	synchronized private void eat() {
		if (num > 0) {
			try {
				// 导致一个资源信息被多个用户同时拿到
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "吃了编号为" + num + "的苹果");
			num--;
		}
	}
}
//Thread.currentThread().getName() 拿到当前线程的引用和名称

public class ImplementDemo {
	public static void main(String[] args) {
		Apple a=new Apple();
		new Thread(a,"A").start();
		new Thread(a,"B").start();
		new Thread(a,"C").start();
	}
}
————————————————————————————华丽的分割线——————————————————————————————

运用synchronized性能并不高,例如JAVA中的Stringbuilder和Stringbuffer的区别:Stringbuffer的append方法加了synchronized保证了安全性,但是性能却比Stringbuilder低,出现了两面性,所以尽量用Stringbuilder,遇到安全问题再做操作。

建议:尽量减小synchronized代码块的大小。

方法三:

锁机制。

public interface Lock

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。 

锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问,如 ReadWriteLock 的读取锁。 


class Apple implements Runnable{
	private int num=50;
	//创建一个锁对象
	private final Lock lock = new ReentrantLock();
	public void run() {
		for(int i=0;i<50;i++){
		eat();
		}		
	}
	
	private void eat() {
		//进入代码块之后立马加锁
		lock.lock();//获取锁
		if (num > 0) {
			try {			
				System.out.println(Thread.currentThread().getName() + "吃了编号为" + num + "的苹果");
				// 导致一个资源信息被多个用户同时拿到
				Thread.sleep(10);
				num--;
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally{
				lock.unlock();
			}
		}
	}
}
//Thread.currentThread().getName() 拿到当前线程的引用和名称

public class ImplementDemo {
	public static void main(String[] args) {
		Apple a=new Apple();
		new Thread(a,"A").start();
		new Thread(a,"B").start();
		new Thread(a,"C").start();
	}
}



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值