Java线程(三):同步与锁

本文通过电影票售卖的例子,展示了多线程环境下资源共享时可能出现的问题,并介绍了如何利用Java中的synchronized关键字来解决线程安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考网址(写得非常好,珍藏网址之一):http://www.blogjava.net/tscfengkui/archive/2010/11/10/337709.html?opt=admin

当两个以上的线程对同一个对象进行操作时,这个对象的属性就难以控制了,会出现很多意外的结果。

举一个在多线程操作当中经典的例子,电影院售票问题。

电影院的窗口可以同时售票,售出的票不能重叠,即不能售出两张11排11号的位置。
    
eg1(非常经典的一段代码):
class Source implements Runnable {
     private int ticket = 10;
     @Override
     public void run() {
            // TODO Auto-generated method stub
            for( int i = 0; i < 50; i++){
                 if( ticket>0){
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                     System. out.println(Thread. currentThread().getName()+ "号窗口售出" + "第" + ticket-- + "张票");
                }
           }
     }
}

public class test9 {

     public static void main(String[] args) {
           
            //只能新建一个source,确保三个线程都是对同一个source操作
           Source source = new Source();
           
            new Thread(source, "A").start();
            new Thread(source, "B").start();
            new Thread(source, "C").start();
     }

}



可以看到C、B都售出标记为1号的票,因为线程C售出1号的票后,没来得及自减,就被线程B访问了!这明显不符合业务的逻辑。

我们需要这样一套机制,当资源正在被某一线程访问的时候,资源被锁住,其他线程访问不了,直到被访问的线程退出使用该资源。

原理图:


很幸运的是,Java已经帮我们实现了这个机制,只要使用 synchronized 关键字就完美解决了这个问题。程序员不用去管Java内部怎么实现这个机制的,只要使用它就可以了。

synchronized 的用法:

1、放方法名前形成同步方法

eg2:
class Source implements Runnable {
     private int ticket = 10;
     @Override
     public void run() {
            // TODO Auto-generated method stub
            for( int i = 0; i < 50; i++){
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                     sale();
                }
     }
     
     public synchronized void sale() {
            if( ticket>0){
                 System.out.println(Thread.currentThread().getName()+ "号窗口售出" + "第" + ticket -- + "张票" );
           }
     }
}

结果:

2、构成 同步块
class Source implements Runnable {
      private int ticket = 10;
      @Override
      public void run() {
            // TODO Auto-generated method stub
            for( int i = 0; i < 50; i++){
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                      synchronized ( this) {
                            if( ticket>0){
                           
                          System. out.println(Thread. currentThread().getName()+ "号窗口售出" + "第" + ticket-- + "张票" );
                           }
                     }    
           }
     }
}

结果:


VIP:synchronized 的位置非常关键,在不同的地方有不同的效果,以下几个例子,读者自行分析。

eg4:

class Source implements Runnable {
      private int ticket = 10;
      @Override
      public void run() {
            // TODO Auto-generated method stub
            for( int i = 0; i < 50; i++){
                 if( ticket>0){
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                      synchronized( this){
                           
                          System. out.println(Thread. currentThread().getName()+ "号窗口售出" + "第" + ticket-- + "张票" );
                     }
                }
           }
     }
}

结果:

eg5:

class Source implements Runnable {
      private int ticket = 10;
      @Override
      public synchronized void run() {
            // TODO Auto-generated method stub
            for( int i = 0; i < 50; i++){
                 if( ticket>0){
                      try {
                           Thread. sleep(1000);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                           
                          System. out.println(Thread. currentThread().getName()+ "号窗口售出" + "第" + ticket-- + "张票" );
                }
           }
     }
}

结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值