博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【java多线程】线程的同步与死锁
阅读量:4185 次
发布时间:2019-05-26

本文共 4737 字,大约阅读时间需要 15 分钟。

文章目录

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

同步问题引出

     下面编写一个简单的卖票程序,将创建若干个线程对象实现卖票的处理操作。

范例: 实现卖票操作

class MyThread implements Runnable {    private  int ticket = 10;  //门票    @Override    public void run() {           while(true) {               if( ticket > 0) {                   System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket --);               } else {                   System.out.println("####票已经卖光了");                   break;               }           }    }}public class DemoThread {    public static void main(String[] args) {          MyThread myThread = new MyThread();          new Thread(myThread,"票贩子A").start();          new Thread(myThread,"票贩子B").start();          new Thread(myThread,"票贩子C").start();    }}

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

class MyThread3 implements Runnable {    private  int ticket = 10;  //门票    @Override    public void run() {           while(true) {               if( 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;               }           }    }}

输出结果可能出现负数现象:

票贩子C卖票,ticket = 3票贩子B卖票,ticket = 3票贩子A卖票,ticket = 2票贩子C卖票,ticket = 1####票已经卖光了票贩子B卖票,ticket = 0####票已经卖光了票贩子A卖票,ticket = -1####票已经卖光了

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

如图,当ticket只剩一张票的时候,票贩子A进入程序,线程休眠了;而之后票贩子B又进入了程序,tikcet还是1,票贩子C同样可以进入程序休眠执行;当线程休眠过后,票贩子A和B同时买到最后一张票,票数变为了0,票贩子C再做卖票操作的时候ticket从0变为-1了。
在这里插入图片描述

线程同步处理

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

     如果要想在程序之中实现这把锁的功能,就可以使用synchronized关键字来实现,利用此关键字可以定义我们的同步方法或同步代码块,在同步代码块的操作里面只允许一个线程进行执行。
1、利用同步代码块进行处理:

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

一般要进行同步对象处理的时候,可以采用当前对象this进行同步。

范例: 利用同步代码解决数据同步访问问题

class MyThread3 implements Runnable {    private  int ticket = 10;  //门票    @Override    public void run() {           while(true) {               synchronized (this) {                   if (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;                   }               }           }    }}

     加入同步处理之后,程序的整体的性能下降了。同步实际上会造成性能的降低。

2、利用同步方法解决:只需要在同步方法添加synchronized关键字

class MyThread3 implements Runnable {    private  int ticket = 10;  //门票    public  synchronized  boolean sale(){        if (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 DemoThread {    public static void main(String[] args) {          MyThread3 myThread = new MyThread3();          new Thread(myThread,"票贩子A").start();          new Thread(myThread,"票贩子B").start();          new Thread(myThread,"票贩子C").start();    }}

     在日后学习java类库的时候会发现,系统中许多的类上使用的同步处理都是同步方法。

线程死锁

     死锁是在进行多线程同步处理之中有可能产生的一种问题,**所谓的死锁之的是若干个线程彼此互相等待的状态。**下面我们通过一个简单的代码来观察一下死锁的表现形式。

范例: 死锁的变现

public class DeadLock implements Runnable{    private Jian jian  = new Jian();    private Xiaoqiang xq = new Xiaoqiang();    public DeadLock() {        new Thread(this).start();       jian.say(xq);    }    @Override    public void run() {        xq.say(jian);    }    public static void main(String[] args) {        new DeadLock();    }}class Jian{    public synchronized void say(Xiaoqiang xq){        System.out.println("阿健说:要想从此过留下买路钱");        xq.get();    }    public synchronized  void get(){        System.out.println("阿健:等我拿到钱就能吃饭了");    }}class Xiaoqiang{    public synchronized  void say(Jian jian){        System.out.println("小强:先让我过去,在给你钱");        jian.get();    }    public  synchronized void get(){        System.out.println("小强:我就可以继续送外卖了");    }}

     现在死锁造成的主要原因是因为彼此都在互相等待着,等待着对方先让出资源。死锁实际上是开发中出现的不确定的状态,有的时候代码如果处理不当,则会不定期出现死锁,这是属于正常开发中的调试问题。

     若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁。

转载地址:http://gjfoi.baihongyu.com/

你可能感兴趣的文章
neo4j初次使用学习简单操作-cypher语言使用
查看>>
hadoop和关系型数据库系统比较
查看>>
Hadoop、Spark等5种大数据框架对比
查看>>
Neo4J简介与安装
查看>>
HBase条件查询(多条件查询)
查看>>
云服务
查看>>
hive的介绍
查看>>
U是什么
查看>>
关系型数据库与NOSQL
查看>>
Sqoop是什么
查看>>
宽带是多少
查看>>
Hadoop和Spark的异同
查看>>
avro 是什么
查看>>
什么叫容灾
查看>>
tower.im、Worktile、钉钉有什么不同
查看>>
OLAP、OLTP的介绍和比较
查看>>
Hadoop ,storm,spark 的特点
查看>>
MapReduce Tez Storm Spark四个框架的异同
查看>>
kudu存储引擎
查看>>
PHP语法1
查看>>