并发同步

多线程不同步的问题(线程不安全)

每个线程都有自己的工作空间,当线程要操作数据时,先从内存中把数据复制到自己的工作空间,然后读取数据或者修改数据,最后用新的数据覆盖原来的数据。
一个线程要修改数据,有三个步骤,1.读取数据到工作空间;2.修改工作空间中的数据;3.用工作空间中的数据覆盖内存中的数据。线程是同时运行的,就会带来一个问题,如果一个线程还没把修改好的数据覆盖到内存,另一个线程就读取了内存中的数据,这样显然程序运行出错,这就是线程不安全的问题。
例如抢票问题,取钱问题,容器的写入(CopyOnWriteArrayList类解决了这个问题)。都要一个线程把数据改完再让另一个线程操作。

不同步问题只出现在改数据的时候,只是读数据不会出现不同步问题

并发

同一个对象多个线程同时操作

同步

在现实当中买票,我们不会出现同一张票被买两次的清空,这是因为我们买票的时候是排队买的,并且当前一个人在买的时候,后面的人都要等前一个人买完后再买。解决多线程也是如此,让线程在看到前面要用的数据其他线程在用时,等待前面的线程用完再继续执行。
前面的线程将数据锁住,后面的线程不能用只能等待前面线程用完数据后再用,从而实现数据的同步

synchronized

线程的同步通过synchronized修饰次来实现,可以修饰方法,叫做同步方法;也可以修饰语句块,叫做同步块。(用法在下面)
注:

  • 因为在实现数据同步的时候,只让一个线程运行,所以会影响性能,并且应为优先级是先执行的概率,所以会出现线程优先级倒置的问题,即低优先级的线程先运行。
  • synchronized锁的是对象,是在内存中的资源。
  • synchronized要合理选择范围,太小会导致锁不住数据,太大会影响程序的效率。

同步方法

同步方法的同步监视器是对象本身即this,即对象本身被锁住。
实际中为了提高效率最好不用同步方法,因为锁的范围大。
在“服务器”中用同步方法,在“用户类”中用同步块。自己总结的,不知道对不对。

package ThreadClass;
/**
 * 测试线程锁 
 * @author 王星宇
 * @date 2020年2月17日
 */
public class safeThread {
	public static void main(String[] args) {
		//一份资源
		SafeWeb12306 web = new SafeWeb12306();
		//多个代理
		new Thread(web,"12306").start();
		new Thread(web,"美团").start();
		new Thread(web,"智行").start();
	}
}
class SafeWeb12306 implements Runnable{

	private int tickets = 10;
	@Override
	public void run() {
		while(true) {
			try {
				//模拟网络延迟
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(rob()) continue;
			else break;
		}
	}
	
	public synchronized boolean rob() {
		if(tickets <= 0) return false; 
		System.out.println(Thread.currentThread().getName() + "抢到一张,还有" + tickets-- + "张");
		return true;
	}
	//为了提高性能,用同步块,双重检测(边界检测)
	public boolean rob2() {
		if(tickets <= 0) return false; 
		synchronized(this) {
			if(tickets <= 0) return false; 
			System.out.println(Thread.currentThread().getName() + "抢到一张,还有" + tickets-- + "张");
		}
		return true;
	}
	
}

同步块

同步块的形式:

synchroinzed(obj){} 

obj称之为同步监视器

同步监视器执行过程:

  • 第一个线程访问,锁定同步监视器,执行其中代码
  • 第二个线程访问,发现同步监视器被锁定,无法访问
  • 第一个线程访问完毕,解锁同步监视器
  • 第二个线程访问,发现同步监视器未锁,锁定并访问
package ThreadClass;
/**
 * 测试同步块
 * 
 * @author 王星宇
 * @date 2020年2月17日
 */
public class safeThread02 {
	public static void main(String[] args) {
		Account aa = new Account(100);
		draw you = new draw(aa,0,70);
		draw girlfriend = new draw(aa,0,80);
		
		new Thread(you,"你").start();
		new Thread(girlfriend,"女朋友").start();
	}
}
//账户
class Account{
	int money;
	public Account (int money) {this.money = money;	}
}
//取钱
class draw implements Runnable{
	private Account account;//账户
	private int poketMoney;//口袋里的钱
	private int drawMoney;//取出来的钱
	public draw(Account account,int poketMoney,int drawMoney) {
		this.account = account;
		this.poketMoney = poketMoney;
		this.drawMoney = drawMoney;
	}
	@Override
	public void run() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		drawMoney();
	}
	//这里加synchronized不能同步
	public void drawMoney() {
		synchronized(account) {
			System.out.println(account.money+ " " + drawMoney);
			if(account.money - drawMoney <= 0) {
				System.out.println("你的账户没钱了");
				return ;
			}
			
			account.money -= drawMoney;
			poketMoney = drawMoney;
			System.out.println(Thread.currentThread().getName() +
					"取出了" + drawMoney + "元," +
					"账户余额:" + account.money);
		}
	}
}

死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形
某一个同步块同时拥有两个以上对象的锁时(锁套锁),就有可能发生“死锁”的问题。
解决方式就是不要锁套锁,让锁并列。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值