多线程之间的共享数据安全问题(临界资源问题)
多个线程访问共享的数据,可能存在数据的不安全。
t1线程访问数据:中途被其他线程抢跑了,它还修改了。。。t1再抢回来,数据已经被改了,就是不安全。
如何解决临界资源的问题?
同步:原子性操作:(化学中表示最小颗粒,不可再分)
计算机中用于表示一次性执行完毕。
同步:一次性执行完毕。
语法:关键字synchronized
同步的原理:利用对象的互斥锁。
每个线程来访问,只能有一个线程进入执行,第一个动作锁对象(上锁)。来保证其他线程不能进入执行。等到该线程结束这个同步代码块或者同步方法,释放锁对象(开锁),才允许其他的线程来访问。
用法一:同步代码块:一次只能被一个线程执行,中间不允许其他线程插入执行的。
//t1,t2,t3,t4线程名字
synchronized(锁对象){//开始给对象上锁,t1
}//打开对象的锁
特征:
A:synchronized小括号里的对象,是锁对象,并要求多线程的情况下,锁对象必须是同一个对象。
B:synchronized大括号里的代码,就是同步执行的代码。或者说是加了锁的代码。意味着每次只能被一个线程执行。
C:同步的代码越少越好,在保证安全的情况下,提高性能。
D:锁对象:理论上谁都可以,只要是多个线程访问的共同对象即可。
this关键字,外面创建对象传入,类名.class,"abc",
用法二:同步方法:一个方法就是同步,只能被一个线程来执行,中间不允许其他线程来打断执行
public synchronized void test(){//锁对象只带this
}
普通的方法:对象调用。锁定的对象,就是this对象。
静态的方法:类调用。锁定的对象,就是类名.class
同步的优缺点:
好处:解决了数据安全的问题
缺点:降低了效率,可能会死锁
线程之间的通信
线程之间的通信:wait(),notify(),notifyAll()
wait()——>让线程进入阻塞状态,暂停执行。一直阻塞
notify()——>唤醒线程,wait()住的线程,被唤醒。如果多个线程wait()了,唤醒其中的一个。
notifyAll()——>唤醒所有。
语法要求:必须在同步中,由同步的锁对象来调用。否则java.lang.IllegalMonitorStateException异常。
生产者消费者模型:
生产者:持有资源,生产产品,存入容器中
消费者:持有资源,消费掉产品。
wait()
当调用该方法时,释放自身所有的锁标记,同时次队列进入等待队列
notif() notifAll()
唤醒 通知释放锁标记的线程