• Java04 线程同步问题解决——线程锁(同步锁、互斥锁)


    目录

    写在最前:

    可能有误,请大家批评指正

    一、线程切换

    Java中,如果要实现在一个线程间的线程切换,需要在线程中使用Thread.yield()即可让出CPU时间。

    二、线程锁(也叫同步锁、互斥锁)

    线程锁可以在有效缩小同步范围的同时,尽可能的保证并发效率

    2.1 使用synchronized关键字对方法进行加锁

    对整个线程处理加锁(严重影响效率,不常用

    2.1.1 语法

    public synchronized void test(){
        
    }
    

    2.1.2 案例

    package com.javase.thread;
    
    import javax.management.RuntimeErrorException;
    
    /**
     * 		这个类主要讲了Sychronized关键字,给方法加了Synchronized关键字以后,线程在调用这个方法时,相当于对这个方法加了锁,
     * 那么其他线程就不能调用这个方法了(处于阻塞状态)
     * 
     * @author gupan
     *
     */
    public class ThreadSyncSychronized {
    	public static void main(String[] args) {
    		final Table2 table = new Table2();
    		Thread t1 = new Thread() {
    			public void run() {
    				while (true) {
    					try {
    						int bean = table.getBean();
    						Thread.yield(); // 线程切换语句,让出CPU时间
    						System.out.println(getName() + ","  + table.getBean());
    					} catch (RuntimeErrorException e) {
    						System.out.println(getName() + ","  + e);
    						break;
    					}
    					
    				}
    			}
    		};
    		
    		Thread t2 = new Thread() {
    			public void run() {
    				while (true) {
    					try {
    						int bean = table.getBean();
    						Thread.yield(); // 线程切换语句,让出CPU时间
    						System.out.println(getName() + ","  + table.getBean());
    					} catch (RuntimeErrorException e) {
    						System.out.println(getName() + "," + e);
    						break;
    					}
    				}
    			}
    		};
    		t2.start();
    		t1.start();
    	}
    }
    
    class Table2{
    	// 桌子上有20元钱
    	private int beans = 20;
    	
    	public synchronized int getBean() throws RuntimeErrorException{
    		if (this.beans == 1) {
    			throw new RuntimeErrorException(null, "地主家没有余粮了");
    		}
    		Thread.yield(); // 线程切换语句,让出CPU时间
    		return this.beans--;
    	}
    }
    

    2.2 使用synchronize关键字对线程方法中的某一部分加锁(同步块的方式)

    2.2.1 语法

    // 注意这里是this,可以写new Object(),但是这样起不到加锁的效果
    // 也就是说,要实现加锁的效果,需要保证是对同一个对象(也就是保证synchronized后面所跟对象是同一个)加锁
    synchronized(this){
        ···
        // 加锁语句
    }
    

    2.2.2 案例

    package com.javase.thread;
    /**
     * 这个类主要演示小范围的使用锁。尽可能的提高并发效率
     * 
     * synchronized(this){
     * 		···
     * 		// 加锁语句
     * }
     * 
     * @author Think
     *
     */
    public class ThreadSyncLock {
    	public static void main(String[] args) {
    		final Shop shop = new Shop();
    		Thread t1 = new Thread() {
    			public void run() {
    				shop.buy();
    			}
    		};
    		
    		Thread t2 = new Thread() {
    			public void run() {
    				shop.buy();
    			}
    		};
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    class Shop{
    	public void buy() {
    		Thread t = Thread.currentThread();
    		try {
    			System.out.println(t.getName() + "正在挑衣服");
    			Thread.sleep(1000);
    			
    			// 需要传入当前方法所属对象,所以这里要传入this
    			synchronized (this) {
    				System.out.println(t.getName() + "正在试衣服");
    				Thread.sleep(1000);
    			}
    			
    			System.out.println(t.getName() + "结账离开");
    			Thread.sleep(1000);
    		}catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    	}
    }
    

    2.3 静态方法加锁

    如果对静态方法加了synchronized关键字,由于静态方法只有一份,整个方法一定是加了互斥锁

    package com.javase.thread;
    
    import com.javase.string.Object;
    
    /**
     * 静态方法的同步
     * 		当一个静态方法被synchronized修饰以后,那么该方法就是同步方法,由于静态方法从属类,
     * 全局就一份,所以同步的静态方法一定具有同步效果,与对象无关
     * 
     * @author gupan
     *
     */
    public class ThreadSyncStatic {	
    	public static void main(String[] args) {
    		Thread t1 = new Thread() {
    			public void run() {
    				Foo.dosome();
    			}
    		};
    		Thread t2 = new Thread() {
    			public void run() {
    				Foo.dosome();
    			}
    		};
    		t1.start();
    		t2.start();
    	}
    }
    
    
    class Foo{
    	public static synchronized void dosome() {
    		try {
    			Thread t = Thread.currentThread();
    			System.out.println(t.getName() + "正在等待运行dosome方法");
    			Thread.sleep(1000);
    			
    			System.out.println(t.getName() + "正在运行dosome方法");
    			Thread.sleep(1000);
    			
    			System.out.println(t.getName() + "执行dosome方法完毕");
    		}catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }
    

    运行结果:

    Thread-1正在等待运行dosome方法
    Thread-1正在运行dosome方法
    Thread-1执行dosome方法完毕
    Thread-0正在等待运行dosome方法
    Thread-0正在运行dosome方法
    Thread-0执行dosome方法完毕
    

    2.3 互斥锁

    2.3.1 同步锁和互斥锁

    同步锁和互斥锁原理相同,存在的是用法上的小差异。当两个线程调用同一段代码,并且,对于两个线程的同步监视器,看到的代码相同,那就是同步锁;但是,对于几段代码,用一个同步监视器进行访问,几段代码不能同时执行,就是互斥锁

    package com.javase.thread;
    /**
     * 这段代码主要演示互斥锁的使用
     * 		使用synchronized修饰这段代码之后,只要他们同步监视器对象相同,那么这几段代码见就是互斥关系,多个线程不能同时执行这些代码
     * 
     * @author gupan
     *
     */
    public class ThreadSyncMatual {
    	/**
    	 * 线程t1和t2不能同时调用methodA或methodB方法,实现互斥关系
    	 * 
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		Boo boo = new Boo();
    		Thread t1 = new Thread() {
    			public void run() {
    				boo.methodA();
    			}
    		};
    		
    		Thread t2 = new Thread() {
    			public void run() {
    				boo.methodB();
    			}
    		};
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    class Boo{
    	public void methodA(){
    		try{
    			Thread t = Thread.currentThread();
    			System.out.println(t.getName() + "正在执行A方法");
    			Thread.sleep(1000);
    			System.out.println(t.getName() + "执行A方法完毕");
    		}catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    	}
    	
    	public void methodB(){
    		try{
    			Thread t = Thread.currentThread();
    			System.out.println(t.getName() + "正在执行B方法");
    			Thread.sleep(1000);
    			System.out.println(t.getName() + "执行B方法完毕");
    		}catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    	}
    }
    
  • 相关阅读:
    贝叶斯推断祭
    libstdc和glibc的一些共享库问题
    nf_conntrack之解决方案
    Too many open files 问题
    Centos系统 上下文切换的检查思路
    GPS坐标转大地坐标
    【转】关于IAP与APP互相跳转的实现
    stm32定时器计数功能
    C库函数——字符串转数字整理
    【转】sscanf函数用法实例
  • 原文地址:https://www.cnblogs.com/gupan/p/9126082.html
Copyright © 2020-2023  润新知