编程语言

同步机制解决线程安全问题(2020-03-31)

2020-03-31  本文已影响0人  _NewMoon

如何解决线程之前提到的线程安全问题?
Java提供了一种同步机制来解决这种问题:

1.同步代码块

我们先介绍synchronized关键字,synchronized关键字是用来给对象和方法或者代码块加锁,同一时刻只有一个线程可以执行加锁的这段代码,其他进程都会被阻塞,等待这段代码执行后,其他线程才能执行这段代码。
我们对线程安全问题引入这篇博客中的Ticket.java进行修改:

Ticket.java

package Thread.Problem;


public class Ticket implements Runnable
{
    //总票数
    private int tik = 100;

    Object obj = new Object();
    @Override
    public void run() {
        while(true) {
            synchronized (obj){
                if(tik>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"is sailing No." + tik);
                    tik--;
                }
            }

        }
    }
}

程序运行结果

Result

我们发现,没有出现之前提到的安全问题,但是从运行结果来看,可以发现所有的票都是从1号窗口(线程0)售卖出去的,那么其他两个线程是不是没有作用,其实,在这个例子中,由于三个线程访问的都是tik这一个数据,所以synchronized锁住的部分在本例中就是售票的那一部分,而在实际情况中,往往会复杂很多,synchronized也只会锁住具体的同步位置,所以,这个例子不能说明synchronized对破坏了多线程特性,但需要承认的是,在这里,同步代码块会降低运行效率,当一个线程执行同步代码块中的代码,其他线程只能死等,等待锁对象的归还。

2.同步方法

顾名思义,就是将方法用synchronized关键字修饰,所以,只需将需要同步的代码抽取出来,重新写一个同步方法,再在run方法中原来被抽取代码的地方调用同步方法即可。

Ticket.java

package Thread.Problem;


public class Ticket implements Runnable
{
  //总票数
  private int tik = 100;

  Object obj = new Object();
  @Override
  public void run() {
      while(true) {
          sailTicket();
      }
  }
  public synchronized void sailTicket(){
      if(tik>0){
          try {
              Thread.sleep(10);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName()+"is sailing No." + tik);
          tik--;
      }
  }
}

输出与上一种方法相同,指出一点,同步方法中sailTicket方法中synchronized锁的对象是this(即类的实例),所以这里的同步方法也可以这样更改:

public void sailTicket(){
        synchronized (this){
            if(tik>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"is sailing No." + tik);
                tik--;
            }
        }
    }

静态同步方法

我们也可以将同步方法设置为静态方法,不过此时synchronized锁的对象就不是this对象锁了,而是类锁,本例中,就是Ticket.class

package Thread.Problem;


public class Ticket implements Runnable
{
    //总票数
    private static int tik = 100;

    Object obj = new Object();
    @Override
    public void run() {
        while(true) {
            sailTicket();
        }
    }
    public static void sailTicket(){
        synchronized (Ticket.class){
            if(tik>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"is sailing No." + tik);
                tik--;
            }
        }
    }
}

上一篇 下一篇

猜你喜欢

热点阅读