• java复习-线程的同步和死锁


    线程的同步和死锁

    同步问题引出

    当多个线程访问同一资源时,会出现不同步问题。比如当票贩子A(线程A)已经通过了“判断”,但由于网络延迟,暂未修改票数的间隔时间内,票贩子B(线程B)也通过了“判断”。此时,若票数只剩下了最后一张,则会出现两个线程同时通过判断并最终会修改票数,出现错误(票数为0或-1)。
    在这里插入图片描述

    线程同步处理

    解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其它线程外面等待。
    在这里插入图片描述

    现这把锁的功能,就可以使用 synchronized 关键字来实现,利用此关键字可以定义同步方法或同步代码块, 在同步代码块的操作里面的代码只允许一个线程执行。

    1. 同步代码块

    synchronized(同步对象){
        同步代码操作;
    }
    
    • 1
    • 2
    • 3

    一般要进行同步对象处理的时候可以采用当前对象 this 进行同步。
    卖票范例(同步代码块版):

    class MyThread implements Runnable { // 线程的主体类
    	private int ticket = 5;
    
    	@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) {
    		MyThread mt = new MyThread();
    		new Thread(mt,"票贩子A").start(); 
    		new Thread(mt,"票贩子B").start(); 
    		new Thread(mt,"票贩子C").start(); 
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    结果:

    票贩子A买票,ticket = 5
    票贩子C买票,ticket = 4
    票贩子C买票,ticket = 3
    票贩子C买票,ticket = 2
    票贩子B买票,ticket = 1
    -----票已售完-----
    -----票已售完-----
    -----票已售完-----

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

    2. 同步方法

    只需要在方法定义上使用synchronized 关键字即可。

    class MyThread implements Runnable { // 线程的主体类
    	private int ticket = 5;
    
    	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) {
    		MyThread mt = new MyThread();
    		new Thread(mt,"票贩子A").start(); 
    		new Thread(mt,"票贩子B").start(); 
    		new Thread(mt,"票贩子C").start(); 
    		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    结果:

    票贩子A买票,ticket = 5
    票贩子A买票,ticket = 4
    票贩子A买票,ticket = 3
    票贩子C买票,ticket = 2
    票贩子C买票,ticket = 1
    -----票已售完-----
    -----票已售完-----
    -----票已售完-----

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

    线程死锁

    死锁是在进行多线程同步的处理之中有可能产生的一种问题,所谓的死锁指的是若干个线程彼此互相等待的状态。
    若干个线程访问同一资源时一定要进行同步处理,而过多的同步会造成死锁。

  • 相关阅读:
    vue-pdf(v4.3.0)
    Python二级 每周练习题27
    Mac brew 安装与使用
    Vue.js 3.x 中跨层级组件如何传递数据?
    【Zookeeper客户端常用的命令&&Zookeeper的核心功能之事件监听】
    如何在 Android 中录制屏幕内容,并以H.264数据流形式发送(屏幕广播)
    是机遇还是挑战?AI 2022五大预测
    求对着目标物体环绕拍摄的相机参数lookAt
    生成模型的两大代表:VAE和GAN
    组合数学(上):数列、排列、组合
  • 原文地址:https://blog.csdn.net/qq_41168765/article/details/132856303