线程安全问题讨论
1.多线程并发操作同一数据时,就可能出现线程安全问题
2.使用同步技术解决,把操作数据的代码进行同步,不要多线程一起操作
案例:铁路售票,一共100张票,四个窗口进行售票
问题案例:
package javastudy01;
public class saleticket extends Thread{
//问题1
//private int ticket = 100 ;这是一个成员对象,下面的每一个对象都会产生自己的100张
//此时所有的对象会共享一个ticket
private static int ticket = 100 ;
public void run(){
while(true){
if(ticket==0){
break;
}
//问题2 :在此处模拟很多方法的同时进行
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("这是第"+ticket-- +"张票");
}
}
public static void main(String[] args) {
//四个线程,相当于四个售票的窗口
new saleticket().start();
new saleticket().start();
new saleticket().start();
new saleticket().start();
}
}
运行时出现问题
出现了卖负数的票;原因:
在方法中加上了睡眠,模拟了多线程同时执行,
当ticket =1时,一号窗口(线程1)在执行到sleep处会睡眠,此时ticket=1,线程2,3,4进入一样会睡眠,
但当1睡醒后,执行下面的代码ticket-- , ticket此时=0 ,然后线程2 醒了,执行ticket--,ticket=-1,跳过了条件
判断的==0 所以会无限执行下去,卖出负数张票。
2.所以解决以上问题需要用到同步技术
多线程并发想改变同一个数据时,建议使用同步代码块
package javastudy01;
import org.omg.CORBA.PRIVATE_MEMBER;
public class saleticket extends Thread{
//问题1
//private int ticket = 100 ;这是一个成员对象,下面的每一个对象都会产生自己的100张
//此时所有的对象会共享一个ticket
private static int ticket = 100 ;
public void run(){
while(true){
//此处锁对象不能使用this,不能用private Object obj = new Object(),
//可以使用 saleticket.class 它是唯一的
synchronized(saleticket.class){
if(ticket==0){
break;
}
//问题2 :在此处模拟很多方法的同时进行
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("这是第"+ticket-- +"张票");
}
}
}
public static void main(String[] args) {
//四个线程,相当于四个售票的窗口
new saleticket().start();
new saleticket().start();
new saleticket().start();
new saleticket().start();
}
}
运行结果
正常买票不出现负票情况;
再给出Runnable接口实现线程安全的代码;
package javastudy01;
public class runnablesale implements Runnable {
public static void main(String[] args) {
runnablesale rs = new runnablesale();
new Thread(rs).start();
new Thread(rs).start();
new Thread(rs).start();
new Thread(rs).start();
}
private int ticket = 100; //此处不需要静态,因为在实现线程过程中rs作为一个对象传入,因而每一个线程的rs是同一个rs
@Override
public void run() {
while(true){
//这里可以使用this是因为rs对象在实现时仅创建了一次,是唯一的
synchronized(this){
if(ticket==0){
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("这是第"+ticket-- +"张票");
}
}
}
}
运行结果
同上