Java基础之线程安全问题

线程安全问题

线程安全为标题

在java程序中,如果有多个线程同时运行,并且同时执行同一段代码,如果程序每次运行的结果和单线程运行的结果是一样的,而且其他变量的值也和预期是一样的,那么这段代码就是线程安全的。

但是在多线程操作中也可能会有一些线程安全的问题发生。

以卖票事例作为说明,有100张票往外售卖,售完结束。

public class Tickets implements Runnable{
   //初始化票数
   private   int ticket=100;

   @Override
   public void run() {
       //卖票
       while (true){
         
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在卖:"+ticket--);
              }
      }
  }
}

 

public class TicketsTest {
   public static void main(String[] args) {
       //声明变量
       Tickets tickets = new Tickets();

       //创建三个线程(窗口)
       Thread t1 = new Thread(tickets,"窗口1");
       Thread t2 = new Thread(tickets,"窗口2");
       Thread t3 = new Thread(tickets,"窗口3");

       //三个窗口同时买票
       t1.start();
       t2.start();
       t3.start();
  }

}

 

但是在运行结果中会发生以下这种情况:票已经卖出,但是总数没有减少;或者票已经售空,仍然在减票的情况

窗口3正在卖:100
窗口1正在卖:99
窗口2正在卖:100
窗口1正在卖:98
.......
窗口2正在卖:4
窗口1正在卖:2
窗口3正在卖:1
窗口2正在卖:1
窗口1正在卖:1

这类问题就称作线程安全问题,为了解决这个问题,可以采取一些线程同步的措施

线程同步

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。

为了解决并发问题(线程同步问题),也就是多线程并发访问同一个资源,对这个资源进行写操作的问题,java中提供了线程同步(synchronized)来解决这个问题。

解决线程同步的方法:

  • 方法1:同步代码块

    • 同步代码块:synchronized加在代码块上,格式如下

    synchronized (lock){
       //需要同步的代码块
      ....
    }

     

  • 方法2:同步锁

    • 对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

      1. 锁对象 可以是任意类型。

      2. 多个线程对象 要使用同一把锁。

  • 方法3:同步方法

    • 在方法进行同步,格式如下:

     public synchronized void method(){
           //需要同步的代码块
          ......
      }
Lock锁

java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。Lock锁也称同步锁,加锁与释放锁方法化了,如下:public void lock() :加同步锁。public void unlock() :释放同步锁。使用如下:

public class Tickets implements Runnable{
   //初始化票数
   private   int ticket=100;
  Lock lock = new ReentrantLock();
   @Override
   public void run() {
       //卖票
       while (true){
               lock.lock();
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在卖:"+ticket--);
              }
               lock.unlock();
      }
  }
}

 

线程安全问题

线程安全为标题

在java程序中,如果有多个线程同时运行,并且同时执行同一段代码,如果程序每次运行的结果和单线程运行的结果是一样的,而且其他变量的值也和预期是一样的,那么这段代码就是线程安全的。

但是在多线程操作中也可能会有一些线程安全的问题发生。

以卖票事例作为说明,有100张票往外售卖,售完结束。

public class Tickets implements Runnable{
   //初始化票数
   private   int ticket=100;

   @Override
   public void run() {
       //卖票
       while (true){
         
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在卖:"+ticket--);
              }
      }
  }
}

 

public class TicketsTest {
   public static void main(String[] args) {
       //声明变量
       Tickets tickets = new Tickets();

       //创建三个线程(窗口)
       Thread t1 = new Thread(tickets,"窗口1");
       Thread t2 = new Thread(tickets,"窗口2");
       Thread t3 = new Thread(tickets,"窗口3");

       //三个窗口同时买票
       t1.start();
       t2.start();
       t3.start();
  }

}

 

但是在运行结果中会发生以下这种情况:票已经卖出,但是总数没有减少;或者票已经售空,仍然在减票的情况

窗口3正在卖:100
窗口1正在卖:99
窗口2正在卖:100
窗口1正在卖:98
.......
窗口2正在卖:4
窗口1正在卖:2
窗口3正在卖:1
窗口2正在卖:1
窗口1正在卖:1

这类问题就称作线程安全问题,为了解决这个问题,可以采取一些线程同步的措施

线程同步

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。

为了解决并发问题(线程同步问题),也就是多线程并发访问同一个资源,对这个资源进行写操作的问题,java中提供了线程同步(synchronized)来解决这个问题。

解决线程同步的方法:

  • 方法1:同步代码块

    • 同步代码块:synchronized加在代码块上,格式如下

    synchronized (lock){
       //需要同步的代码块
      ....
    }

     

  • 方法2:同步锁

    • 对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

      1. 锁对象 可以是任意类型。

      2. 多个线程对象 要使用同一把锁。

  • 方法3:同步方法

    • 在方法进行同步,格式如下:

     public synchronized void method(){
           //需要同步的代码块
          ......
      }
Lock锁

java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。Lock锁也称同步锁,加锁与释放锁方法化了,如下:public void lock() :加同步锁。public void unlock() :释放同步锁。使用如下:

public class Tickets implements Runnable{
   //初始化票数
   private   int ticket=100;
  Lock lock = new ReentrantLock();
   @Override
   public void run() {
       //卖票
       while (true){
               lock.lock();
               if(ticket>0){
                   try {
                       Thread.sleep(50);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
                   System.out.println(Thread.currentThread().getName()+"正在卖:"+ticket--);
              }
               lock.unlock();
      }
  }
}

 

posted @ 2018-10-23 16:05  Aimaybe  阅读(160)  评论(0编辑  收藏  举报