多线程安全问题
1.1解决线程安全问题的基本思想
(1)原因:当程序的多条语句在操作线程共享数据时(如买票例子中的票就是共享资源),
由于线程的随机性导致,一个线程对多条语句,执行了一部分还没执行完,另一个线程抢夺
到cpu 执行权参与进来执行,此时就导致共享数据发生错误。比如买票例子中打印重票和
错票的情况。
(2)解决方法:对多条操作共享数据的语句进行同步
首先想为什么出现问题?(也是我们判断是否有问题的标准)
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
如何解决多线程安全问题呢?
基本思想:让程序没有安全问题的环境。
怎么实现呢?
把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
.2Java 中多线程同步是什么?
同步是用来解决多线程的安全问题的,在多线程中,同步能控制对共享数据的访问。
如果没有同步,当一个线程在修改一个共享数据时,而另外一个线程正在使用或者更新同一
个共享数据,这样容易导致程序出现错误的结果。
1.3什么是锁?锁的作用是什么?
锁就是对象, 锁的作用是保证线程同步,解决线程安全问题。
持有锁的线程可以在同步中执行,没有锁的线程即使获得cpu 执行权,也进不去。
1.4同步的前提
(1)必须保证有两个以上线程
(2)必须是多个线程使用同一个锁,即多条语句在操作线程共享数据
(3)必须保证同步中只有一个线程在运行
1.5. 同步的好处和弊端
好处:同步解决了多线程的安全问题
弊端:多线程都需要判断锁,比较消耗资源
1.6解决线程安全问题实现1
(1)同步代码块:
可以指定需要获取哪个对象的同步锁,使用synchronized 的代码块同样需要锁,但
他的锁可以是任意对象,考虑到安全问题,一般还是使用同一个对象,相对来说效率较高。
注意:
虽然同步代码快的锁可以使任何对象,但是在进行多线程通信使用同步代码快时,
必须保证同步代码快的锁的对象和,否则会报错。
同步方法的锁是this,也要保证同步方法的锁的对象和调用wait、notify 和
notifyAll 的对象是同一个对象,也就是都是this 锁代表的对象。
格式:
synchronized(对象){需要同步的代码;}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
同步代码块的对象可以是哪些呢?
下面就电影院买票问题进行说明:
package java.thread;
/**
* 线程同步
*/
public class ThreadDemo4 {
public static void main(String[] args) {
Saler s1 = new Saler("s1",1);
Saler s2 = new Saler("s2",1);
s1.start();
s2.start();
}
}
/**
* 售票员
*/
class Saler extends Thread {
//总票数
private static int tickets = 100 ;
private String name0;
private int sleep;
public Saler(String name0, int sleep) {
this.name0 = name0;
this.sleep = sleep;
}
public String getName0() {
return name0;
}
public void setName0(String name0) {
this.name0 = name0;
}
public void run() {
try {
while(true){
int temp = 0 ;
synchronized (Saler.class){
temp = tickets ;
Thread.sleep(50);
tickets -- ;
}
if(temp <= 0 ){
return ;
}
else{
System.out.println(name0 +" : " + temp);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}