• Java 线程的同步与死锁


    概念:Java同步和异步,阻塞和非阻塞

    1、线程的同步产生的原因

    没有同步的情况

    class MyThread1 implements Runnable
    {
        private int ticket=5;
        @Override
        public void run() {
            for(int x =0;x<20;x++)
            {
    
                if(ticket>0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
                }
            }
        }
    
    }
    public class Test {
        public static void main(String[] args) {
            MyThread1 mt = new MyThread1();
            new Thread(mt,"票贩子A").start();
            new Thread(mt,"票贩子B").start();
            new Thread(mt,"票贩子C").start();
            new Thread(mt,"票贩子D").start();
        }
    }
    
    票贩子C卖票:5
    票贩子D卖票:5
    票贩子B卖票:4
    票贩子A卖票:3
    票贩子D卖票:2
    票贩子C卖票:1
    票贩子A卖票:-1
    票贩子B卖票:0
    票贩子D卖票:-2
    

    可以看到又相同的票被卖了,还出现了负数票的情况。

    2、线程的同步处理操作

    实现同步的关键字synchronized,可以通过两种方式使用

    • 一种是同步代码块
    • 另外一种是同步方法
      在Java里面有四种代码块:普通代码块、构造块、静态块、同步块

    使用同步代码块实现同步

    class MyThread1 implements Runnable
    {
        private int ticket=10;
        @Override
        public void run() {
    
            for(int x =0;x<20;x++)
            {
                synchronized(this){
                    if(ticket>0) {
                        System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
                    }
                }
            }
        }
    
    }
    public class SynchronizedThread {
        public static void main(String[] args) {
            MyThread1 mt = new MyThread1();
            new Thread(mt,"票贩子A").start();
            new Thread(mt,"票贩子B").start();
            new Thread(mt,"票贩子C").start();
            new Thread(mt,"票贩子D").start();
        }
    }
    
    票贩子A卖票:10
    票贩子D卖票:9
    票贩子C卖票:8
    票贩子B卖票:7
    票贩子C卖票:6
    票贩子C卖票:5
    票贩子C卖票:4
    票贩子D卖票:3
    票贩子A卖票:2
    票贩子D卖票:1
    

    调用同步方法实现同步

    class MyThread1 implements Runnable
    {
        private int ticket=10;
        @Override
        public void run() {
            for(int x =0;x<20;x++)
            {
                this.sale();
            }
        }
        public  synchronized void sale()
        {
            if(ticket>0) {
                System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
            }
        }
    
    }
    public class SynchronizedThread {
        public static void main(String[] args) {
            MyThread1 mt = new MyThread1();
            new Thread(mt,"票贩子A").start();
            new Thread(mt,"票贩子B").start();
            new Thread(mt,"票贩子C").start();
            new Thread(mt,"票贩子D").start();
        }
    }
    

    3、线程的死锁情况

    Java 实例 - 死锁及解决方法
    死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

    java 死锁产生的四个必要条件:
    1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
    2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
    3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
    4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

    解决方法:

    • 用信号量去控制死锁。
    • 调整申请锁的范围
    • 调整申请锁的顺序

    避免死锁:银行家算法。

    请解释多个线程访问统一资源时需要考虑哪些情况?有可能带来哪些后果?

    多个线程访问同一资源时要考虑到线程间的同步问题,可以使用同步代码或同步方法解决;
    同步代码块:synchronized(锁定对象){代码}
    同步方法: public synchronized 返回值 方法名称(){代码}
    但是过多的使用同步,有可能造成死锁。

    --------------- 我每一次回头,都感觉自己不够努力,所以我不再回头。 ---------------
  • 相关阅读:
    cmd 新建空文件
    查看Linux版本
    centos7时间调整
    正确卸载vs2015及以前版本方式
    vs2017,vs2019 无法连接到Web服务器“IIS Express”
    .netcore开发环境和服务器注意事项
    .netcore 网站启动后 502.5
    CentOS7开机报错piix4_smbus ****host smbus controller not enabled
    centos7 升级系统后,启动界面出现多个选项
    .gitkeep文件
  • 原文地址:https://www.cnblogs.com/zjw-blog/p/13649612.html
Copyright © 2020-2023  润新知