java多线程三:线程的同步与死锁

文章出处 https://www.jianshu.com/p/b913e64db7ee

文章对应视频出处:https://developer.aliyun.com/course/1012?spm=5176.10731542.0.0.6ef2d290hxQ4g0

在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,当然多个线程访问同一资源时如果处理不当,就会产生数据的错误操作。

同步问题的引出

  现在编写一个简单的卖票程序,将若干个线程对象实现卖票的处理操作。
范例:实现卖票操作

class MyThread implements Runnable {
    private int ticket = 10;//总票数为10张
    @Override
    public void run() {
        while (true) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
            } else {
                System.out.println("***** 票卖光了 *****");
                break;
            }
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt=new MyThread();
        new Thread(mt,"票贩子A").start();
        new Thread(mt,"票贩子B").start();
        new Thread(mt,"票贩子C").start();
    }
}

  此时的程序将创建3个线程对象,并且这三个线程将进行10张票的出售。此时的程序在进行卖票处理的时候,并没有任何的问题(假象),下面可以模拟一下卖票中的延迟操作。

class MyThread implements Runnable {
    private int ticket = 10;//总票数为10张
    @Override
    public void run() {
        while (true) {
            if (this.ticket > 0) {
                try {
                    Thread.sleep(100);//模拟网络延迟
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
            } else {
                System.out.println("***** 票卖光了 *****");
                break;
            }
        }
    }
}

 这个时候追加了延迟问题就暴露出来了,而实际上这个问题一直都在。

线程同步

  经过分析之后已经可以确定同步问题产生的主要原因了,那么下面就需要进行同步问题的解决,但是解决问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待;

 如果想程序中实现锁功能,就可以使用synchronized关键字来是吸纳,利用synchronized可以定义同步方法和同步代码块,在同步代码块的操作中的代码只允许一个线程执行。
1、利用同步代码块进行处理:

synchronized (同步对象){
    同步代码操作;
}

 一般要进行同步对象处理时,可以采用当前对象this进行同步。
  范例:利用同步代码块解决数据同步访问问题

class MyThread implements Runnable {
    private int ticket = 1000;//总票数为10张
    @Override
    public void run() {
        while (true) {
            synchronized (this) {//每一次只允许一个线程进行访问
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(100);//模拟网络延迟
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
                } else {
                    System.out.println("***** 票卖光了 *****");
                    break;
                }
            }
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "票贩子A").start();
        new Thread(mt, "票贩子B").start();
        new Thread(mt, "票贩子C").start();
    }
}

  加入同步处理之后,程序的整体性能下降了。同步实际上会造成性能的降低
2、利用同步方法解决:只需要在方法定义上使用synchronized关键字即可。

class MyThread implements Runnable {
    private int ticket = 10;//总票数为10张
    public synchronized boolean sale() {
        if (this.ticket > 0) {
            try {
                Thread.sleep(100);//模拟网络延迟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
            return true;
        } else {
            System.out.println("***** 票卖光了 *****");
            return false;
        }
    }
    @Override
    public void run() {
        while (this.sale()) {}
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "票贩子A").start();
        new Thread(mt, "票贩子B").start();
        new Thread(mt, "票贩子C").start();
    }
}

 在日后学习Java类库时,系统中许多的类上使用的同步处理采用的都是同步方法。

死锁

  死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。

public class DeadLock implements Runnable {
    private Producer producer = new Producer();
    private Customer customer = new Customer();
    public DeadLock() {
        new Thread(this).start();
        customer.say(producer);
    }
    public static void main(String[] args) {
        new DeadLock();
    }
    @Override
    public void run() {
        producer.say(customer);
    }
}
class Producer {
    public synchronized void say(Customer customer) {
        System.out.println("店员:先买单后吃饭");
        customer.get();
    }
    public synchronized void get() {
        System.out.println("收到钱,可以给你做饭了");
    }
}
class Customer {
    public synchronized void say(Producer producer) {
        System.out.println("顾客:先吃饭后买单");
        producer.get();
    }
    public synchronized void get() {
        System.out.println("吃饱饭了,可以买单了");
    }
}

 现在死锁造成的主要原因是因为彼此都在互相等待着,等待着对方先让出资源。死锁实际上是一种开发中出现的不确定的状态,有时代码处理不当,则会不定期出现死锁,这属于正常开发中的调试问题。
  若干个线程访问同一资源时一定要进行同步处理,但过多的同步会造成死锁。

发布了52 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/YKWNDY/article/details/104644565