多线程程序存在安全问题
得到的结果是11 12
这种是一种理想化状态的结果.
怎样解决这种安全问题
当一个线程在执行过程中,如果没有执行完,那么其它的
线程给我等待,当前线程执行完成后,其它的线程才允许
去执行内容,这样就可以解决这个线程安全问题.
代码实现 我们可以使用synchronized关键字来操作。
让线程进行同步
怎样使用
同步代码块
格式 synchronized(任意对象){
内容
}
相当于加了锁,也就是说当前线程没有执行完内容,
这把锁不会释放,其它线程想要执行,必须得到锁才
可以执行。
也可以使用另外一种方式进行同步
同步方法 就是在执行的方法上用synchronized进行修饰
但是它降低了多线程程序的效率.
同步什么时候使用?
1.多线程时使用同步
2.在线程执行的内容中,操作了共享数,并且是多条件语句操作,这时就需要同步
同步使用时要注意的问题?
我们必须保证想要同步的这些线程所使用的锁的对象必须是
同一个。
class Demo8 { public static void main(String[] args) { ThreadDemo td=new ThreadDemo(); Thread th1=new Thread(td); Thread th2=new Thread(td); th1.start(); th2.start(); } } class ThreadDemo implements Runnable { int id=10; Object obj=new Object(); public synchronized void run(){ //synchronized(obj){ //id++; /* 当第一个线程执行到这个位置时,有可能让当前线程改变成 临时堵塞状态,而第二个线程变成运行状态。 如果这种情况出现,结果是多少? */ //人为让当前正在执行的线程释放执行权 /*try{ Thread.sleep(1); //释放执行权,没有释放锁. }catch(Exception e){ }*/ System.out.println(id++); //} } }
2.
线程安全问题练习
银行帐户中有500块钱,两个人一起去取钱。
利用多线程模拟这个操作
class Test3 { public static void main(String[] args) { Bank bank=new Bank(); Thread th1=new Thread(bank); Thread th2=new Thread(bank); th1.setName("张三"); th2.setName("张小三"); th1.start(); th2.start(); } } class Bank implements Runnable { Person p=new Person(); Object obj=new Object(); public void run(){ //synchronized(new Object()){ //出现了问题,这时每个线程在启动时都会new Object(), //我们在同步时,想要让多个线程同步,使用锁必须是同一个对象 getMoney(500); //} } public synchronized void getMoney(double money){ if(p.money>=money){ try{ Thread.sleep(1); }catch(Exception e){ } p.money-=money; //取完钱 System.out.println(Thread.currentThread().getName()+"取到了"+money+"元"); }else{ System.out.println(Thread.currentThread().getName()+"没有取到"); } } } class Person { double money=500; }
模拟卖票程序 有100张票,四个人去买这些票
显示出每个人都买到了第几号票
分析:因为这四个人谁能买到第几张票是随机的所有使用多线程来操作
当前程序出现的问题?
我们相当于两个窗口同时去售票,
那么我们使用的这四个线程对象可以
在两个窗口中任意的一个去买票。
票只有100张,我们在两个售票窗口的方法中,
都使用了同步.
问题是 sellTicket1所使用是同步方法,那么同步方法使用的锁是什么?
sellTicket2所使用的是同步代码块,它所使用的锁是obj
多线程程序中要想保证当前线程是同步的,必须保证使用同一个锁。
同步方法其实也使用的锁,他的锁对象是this。
那么如果你在多线程程序中同步方法与同步代码块共同出现,为了保证
使用同一把锁,这个时候同步代码块所使用的对象也要是this
class Test5 { public static void main(String[] args) { TicketWindow tw=new TicketWindow(); Thread th1=new Thread(tw); Thread th2=new Thread(tw); Thread th3=new Thread(tw); Thread th4=new Thread(tw); th1.setName("张三"); th2.setName("李四"); th3.setName("王五"); th4.setName("赵六"); th1.start(); th2.start(); th3.start(); th4.start(); } } /* 售票窗口 */ class TicketWindow implements Runnable { static int ticket=100; //代表100张票 //Object obj=new Object(); static boolean flag=true;//开关,可以让四个线程都去执行这两个售票窗口. //售票方法 public static synchronized void sellTicket1(){ //当前的同步方法所使用的锁对象是哪个对象? 默认使用的锁就是this //如果是static方法,所使用的锁是 类名.class 对象 flag=false; if(ticket>0){ System.out.println(Thread.currentThread().getName()+" 买到了第"+ticket+"张票"); ticket--; } } //售票方法 public void sellTicket2(){ flag=true; synchronized(TicketWindow.class){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+" 买到了第"+ticket+"张票"); ticket--; } } } public void run(){ while(true){ if(flag){ sellTicket1(); }else{ sellTicket2(); } } } } /* 解决安全问题 1. 同步代码块 2. 同步方法 同步方法,如果方法是实例方法,那么它默认所使用的锁是 this 如果同步方法是静态的方法,那么它默认所使用的锁的 类名.class 对象. */