多线程_并发_同步_synchronized方法_synchronized块

在这里插入图片描述

synchronized方法

package com.sxt.syn;
/**
 * 线程安全: 在并发时保证数据的正确性、效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块
 * @author 
 *
 */
public class SynTest01 {

	public static void main(String[] args) {
		//一份资源
		SafeWeb12306 web =new SafeWeb12306();
		//多个代理
		new Thread(web,"码畜").start();
		new Thread(web,"码农").start();
		new Thread(web,"码蟥").start();;
	}

}

class SafeWeb12306 implements Runnable{
	//票数
	private int ticketNums =10;
	private boolean flag = true;
	@Override
	public void run() {
		while(flag) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			test();
		}
	}	
	//线程安全  同步
	public synchronized void test() {
		if(ticketNums<=0) {
			flag = false;
			return ;
		}
		//模拟延时
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
	}
}

synchronized是锁对象的资源。
我们数据都是在方法里面操作的,我们通过方法就可以去控制这个数据了。通过块也能去保证数据的安全。
锁了(方法)资源,这个资源是对象的资源,那此时这个对象是this,方法里面的资源是不是都是和这个对象相关的资源,如果不是就琐失败了。

package com.sxt.syn;
/**
 * 线程安全: 在并发时保证数据的正确性、效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块 
 * @author 
 *  
 */
public class SynTest02 {
	public static void main(String[] args) {		
		//账户
		Account account =new Account(100,"结婚礼金");
		SafeDrawing you = new SafeDrawing(account,80,"可悲的你");
		SafeDrawing wife = new SafeDrawing(account,90,"happy的她");
		you.start();
		wife.start();
	}
} 

class Account{
	int money; //金额
	String name; //名称
	public Account(int money, String name) {
		this.money = money;
		this.name = name;
	}

 
//模拟取款
class SafeDrawing extends Thread{
	Account account ; //取钱的账户
	int drawingMoney ;//取的钱数
	int packetTotal ; //口袋的总数	
	
	public SafeDrawing(Account account, int drawingMoney,String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
	}

	@Override
	public void run() {
		test();
	}
	//目标不对锁定失败  这里不是锁this 应该锁定 account
	public synchronized void test() {
		if(account.money -drawingMoney<0) {
			return; 
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		account.money -=drawingMoney;
		packetTotal +=drawingMoney;
		System.out.println(this.getName()+"-->账户余额为:"+account.money);
		System.out.println(this.getName()+"-->口袋的钱为:"+packetTotal);
	}
}

一定要理解到位:什么时候锁上了,什么时候没锁上,为什么要锁它,线程不安全是哪里造成的,原因是什么。一定要学会分析,比如刚刚的负数、相同的情况是怎么产生的啊,加了synchronized为什么没锁上,这些都是线程的难点。

synchronized块
在这里插入图片描述
注:
刚刚我们发现使用同步方法锁的这个资源的对象不对,因为默认情况下这个成员方法是this,因此,我要锁一个具体的对象该怎么办呢?借助synchronized同步块!
synchronized同步块在小括号里面填入的是一个具体的对象,比如丢入Account对象、this或者丢入模子的信息,小括号里才是我们需要锁定的对象。然后花括号里面写入代码,我们将花括号的代码一般来说就称为块,加入了synchronized就称为“同步块”。
Java里面的块有四种:
1、方法里面写一个块,我们称为局部块(普通块),用来解决变量的作用域,快速释放内存;
2、如果是在类中方法外写一个块,这个块我们称为构造块,作用和构造器一样,用来初始“对象”信息的。
3、如果在构造块上加一个static,我们称为静态块,静态块和构造块的区别是:静态块加载一次是用于初始化类的,先于构造块执行。
4、最后一个是同步块,也是在方法里面,用于解决线程安全的问题。

同步监视器的执行过程:
在这里插入图片描述

package com.sxt.syn;
/**
 * 线程安全: 在并发时保证数据的正确性、效率尽可能高
 * synchronized
 * 1、同步方法
 * 2、同步块 ,目标更明确
 * @author 
 *  
 */
public class SynBlockTest01 {
	public static void main(String[] args) {		
		//账户
		Account account =new Account(1000,"结婚礼金");
		SynDrawing you = new SynDrawing(account,80,"可悲的你");
		SynDrawing wife = new SynDrawing(account,90,"happy的她");
		you.start();
		wife.start();
	}
} 
 //模拟取款 线程安全
class SynDrawing extends Thread{
	Account account ; //取钱的账户
	int drawingMoney ;//取的钱数
	int packetTotal ; //口袋的总数	
	
	public SynDrawing(Account account, int drawingMoney,String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
	}

	@Override
	public void run() {
		test() ;
	}
	//目标锁定account
	public  void test() {
		//提高性能
		if(account.money<=0) {
			return ;
		}
		//同步块
		synchronized(account) {
			if(account.money -drawingMoney<0) {
				return; 
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			account.money -=drawingMoney;
			packetTotal +=drawingMoney;
			System.out.println(this.getName()+"-->账户余额为:"+account.money);
			System.out.println(this.getName()+"-->口袋的钱为:"+packetTotal);
		}
	}
}


package com.sxt.syn;

import java.util.ArrayList;
import java.util.List;

/**
 * 线程安全:操作容器
 * 
 * @author  *
 */
public class SynBlockTest02 {
	public static void main(String[] args) throws InterruptedException {
		List<String> list = new ArrayList<String>();
		for(int i=0;i<10000;i++) {
			new Thread(()->{
				//同步块
				synchronized(list) {
					list.add(Thread.currentThread().getName());
				}
			}) .start();
		}
		Thread.sleep(10000);
		System.out.println(list.size());
	}
}

上面的案例除了main方法没有其他方法,我们锁main方法没有用,方法中使用的是lambda表达式,所以没有方法我们锁谁呢?我们锁不了main方法,只能锁List。synchronized(list){list.add(Thread.currentThread().getName());}。在添加的时候保证是拿到锁的。
在上面这个案例中如果没有加最后的Thread.sleep(),最后执行的结果也是不正确的,这是因为main方法中有“多个线程”和“主线程”,“多个线程”没有执行完,main方法就先执行完了–>System.out.println(list.size());

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值