线程安全
原因:
因为多个线程同时操作一个数据,会导致数据错乱,所以为了避免这个问题,我们需要对数据操作进行锁定,保证数据的同时只能被一条线程操作
解决方法:锁与同步
锁:
可以使用任何一个对象作为锁对象
注意:但是多个线程同时操作一个数据时,要保证锁对象是同一个对象
同步:
关键字: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;
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() {
A.aTest();
}
});
thread.start();
synchronized (A.class) {
System.out.println("进入主线程main方法");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("即将结束主线程main方法");
}
}
}
class A{
public synchronized static void aTest() {
System.out.println("进入aTest方法中");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
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
}
}
原理:多个线程互相持有对方所需的锁对象,导致这几个线程无法正常运行所以在写代码时要尽量避免死锁
注意:尽量不要再同步中使用同步
作业:使用四个线程,编写一个死锁,使四个线程都无法正常结束
生产者与消费者模式
生产者线程
无限执行生产任务
消费者线程
无限执行消费任务
工厂
库存数量
最大库存数量
生产的方法:同步
消费的方法:同步