Java基础——线程安全

线程安全

原因:

因为多个线程同时操作一个数据,会导致数据错乱,所以为了避免这个问题,我们需要对数据操作进行锁定,保证数据的同时只能被一条线程操作

解决方法:锁与同步

锁:
	可以使用任何一个对象作为锁对象
	注意:但是多个线程同时操作一个数据时,要保证锁对象是同一个对象
同步:
	关键字:synchronized
	可以修饰:
    	代码块
    		语法:
    			synchronized(锁对象){
    				//锁对象关闭
    				需要同步的代码
    				//锁对象打开
    			}
    		锁对象:是填入的对象
    	方法:
    		语法:
    			访问权限修饰符 synchronized 返回值类型 方法名(形参列表){
    				//锁对象关闭
    				方法体
    				return 返回值;
    				//锁对象打开
    			}
    		锁对象:谁调用该方法,锁对象就是谁
    	静态方法:
    		语法:
    			访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){
    				//锁对象关闭
    				方法体
    				return 返回值;
    				//锁对象打开
    			}
    		锁对象:该方法所属的类的类对象,一个类只有一个对象

举例说明

举例1:
	1、有一张银行卡里面有50000块钱
	2、银行还给了一个存折
	3、拿着银行卡去取钱
	4、拿着存折去取钱
举例2:
	有一辆火车,从西安开往北京,有200张票,同时交给四个窗口售票
当多个线程同时操作一个数据时会引起数据安全的问题

解决线程安全问题

思路:因为是多个线程同时操作一个数据,会导致数据安全问题,所以只要保证数据同时只能被一条线程操作,就可以解决该问题

所以我们使用锁来解决该问题,但是要保证锁对象是同一个

关键字:synchronizde

可以修饰:
	1、代码块
		synchronizde(锁对象){
			//关闭锁
			要同步的代码
			//开启锁
		}
		同步代码:同时只能被一条线程执行的代码,称为同步代码,反之,同时可以被多个线程操作的代码称为异步代码
		锁对象:任何一个类的对象都可以做为锁对象
	2、普通方法
		语法:
			访问权限修饰符 synchronized 返回值类型 方法名(形参列表){
				//锁对象关闭
    			方法体
    			return 返回值;
    			//锁对象打开
			}
		锁对象:谁调用这个方法,锁对象就是谁
	3、静态方法
		语法:
			访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){
				//锁对象关闭
    			方法体
    			return 返回值;
    			//锁对象打开
			}
		锁对象:该方法所属的类的类对象,一个类只有一个对象
练习:用代码证明synchronized修饰普通方法与静态方法的锁对象是谁?
package com.qianfen.Test;
//用代码证明synchronized修饰普通方法与静态方法的锁对象是谁?
public class Test01 {
	public static void main(String[] args) {
		A a = new A();
		Class<? extends A> class1 = a.getClass();
		
		Thread thread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				A.aTest();
			}
		});
		thread.start();
		
		synchronized (A.class) {
			System.out.println("进入主线程main方法");
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("即将结束主线程main方法");
		}
	}
}
class A{
	public synchronized static void aTest() {
		System.out.println("进入aTest方法中");
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("即将结束aTest方法");
	}
}

线程间通讯

以下的方法是Object类提供的
等待:
	wait();				在那个线程调用该方法,就是让该线程无限期等待,会释放锁对象
	wait(long timeout)	在那个线程调用该方法,就是让该线程有限期等待,会释放锁对象
通知:
	noyify()			使用那个对象调用该方法,就随机唤醒一条以该对象作为锁的线程
	notifyAll()			使用那个对象调用该方法,就唤醒所有以该对象作为锁的线程
	
注意:
	1、只能在同步代码中使用,并且该同步代码的锁对象就是调用以上方法的对象,不然不会出现IllegalMonitorStateException异常
	2、以上方法是Object提供的
Thread:是线程类
创建一个Thread类的对象作用是什么?
	一条新的执行路径,这条路径中执行的代码都在run方法中
作用:使项目同时可以执行多个任务

死锁

原因:
	线程1执行A任务
		sy....(a1){
			xxxx 		//a1锁了
			xxxx
			sy...(b1){
				xxx
				xxx
			}
		}
	线程2执行B任务
		sy....(b1){
			xxx 		//b1锁了
			xxxx
			sy....(a1){
				xxxx
				xxxx
			}
		}
原理:多个线程互相持有对方所需的锁对象,导致这几个线程无法正常运行所以在写代码时要尽量避免死锁
注意:尽量不要再同步中使用同步

作业:使用四个线程,编写一个死锁,使四个线程都无法正常结束

生产者与消费者模式

生产者线程
	无限执行生产任务
消费者线程
	无限执行消费任务
工厂
	库存数量
	最大库存数量
	生产的方法:同步
	消费的方法:同步
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值