• synchronized互斥锁实例解析



    synchronized是Java提供的内置锁,里边有类锁和对象锁;

    在静态方法中,我们一般使用类锁,在实例方法中,我们一般使用对象锁

    sleep是带锁沉睡,sleep方法是在阻塞当前线程继续执行的同时,并持有该对象锁,所以该对象的其他同步线程是无法执行的,不是同一个对象的同步线程是可以执行的

    synchronized互斥锁实例解析

    1、互斥锁基础使用:防止多个线程同时访问对象的synchronized方法。

    只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。

    1.1、多个线程调用同一个方法

    1.1.1、不加互斥锁时

    多个线程,cpu时间片切换的时候,会出现执行到一部分,切换到其它线程的情况,导致输出混乱。

    public class MyThread {
    
        public static void main(String[] args) {
            MyThread s = new MyThread();
            s.thread();
    
        }
    
        public void thread() {
    
            final Printer p = new Printer();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(10);
                            p.print("1111111111");
                        } catch (Exception e) {
    
                        }
                    }
                }
            }, "t1").start();
    
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(10);
                            p.print("2222222222");
                        } catch (Exception e) {
    
                        }
    
                    }
                }
            }, "t2").start();
        }
    
    
        class Printer {
            //synchronized
            public void print(String str) {
    //			synchronized(this){
                for (int i = 0; i < str.length(); i++) {
                    System.out.print(str.charAt(i));
                }
                System.out.println();
                System.out.println("上面执行的是线程:" + Thread.currentThread().getName());
    //		}
            }
        }
    }
    

    输出结果片断:

    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    11122222221111111222
    
    上面执行的是线程:t2
    上面执行的是线程:t1
    2111222222222
    上面执行的是线程:t2
    1111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    12111111111222222222
    
    上面执行的是线程:t2
    上面执行的是线程:t1
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    

    1.1.2、加互斥锁后

    package cn.itcast_01_mythread.thread.thread;
    
    /*
     * 线程安全问题
     */
    public class MyThread {
    
    	public static void main(String[] args) {
    		MyThread s=new MyThread();
    		s.thread();
    
    	}
    
    	public void thread(){
    
    		final Printer p=new Printer();
    		new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				while(true){
    				try{
    					Thread.sleep(10);
    					p.print("1111111111");
    				}catch(Exception e){
    
    				}
    				}
    			}
    		},"t1").start();
    
    new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				while(true){
    				try{
    					Thread.sleep(10);
    					p.print("2222222222");
    				}catch(Exception e){
    
    				}
    
    			}
    			}
    		},"t2").start();
    	}
    
    
    	class Printer{
    		//synchronized
    		public  synchronized void print(String str){
    //			synchronized(this){
    			for(int i=0;i<str.length();i++){
    				System.out.print(str.charAt(i));
    			}
    			System.out.println();
    			System.out.println("上面执行的是线程:"+Thread.currentThread().getName());
    //		}
    		}
    		}
    	}
    
    
    

    输出结果:不会出现错位位置

    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    上面执行的是线程:t1
    2222222222
    上面执行的是线程:t2
    1111111111
    

    1.2、多个线程多个锁,升级为类锁

    1.2.1、未升级成类锁前

    package cn.itcast_01_mythread.thread.thread;
    
    /**
     * 多个线程多个锁
     * @author HL
     *
     */
    public class MyThread2 {
    	private static int age=0;
    	
    	public static void main(String[] args) {
    		final MyThread2 m1=new MyThread2();
    		final MyThread2 m2=new MyThread2();
    		Thread t1=new Thread(new Runnable() {
    			@Override
    			public void run() {
    				m1.printNum("zs");
    			}
    		});
    		
    		Thread t2=new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				m2.printNum("lisi");
    				
    			}
    		});
    		
    		t1.start();
    		t2.start();
    	}
    
    	public synchronized void printNum(String name){
    			try {
    				if(name.equals("zs")){
    					age=18;
    					System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    					System.out.println("thread zs do something");
    					Thread.sleep(1000);
    				}else{
    					age=20;
    					System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    					System.out.println("thread lisi do something");
    				}
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    		System.out.println("name="+name+"----age="+age);
    	}
    }
    

    输出结果:

    当前调用printNum线程是Thread-0
    thread zs do something
    当前调用printNum线程是Thread-1
    thread lisi do something
    当前调用printNum线程是Thread-1
    name=lisi----age=20
    当前调用printNum线程是Thread-0
    name=zs----age=20
    

    2.2.2、加上static关键字,升级为类锁后

    当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程无法执行。

    而getValue并没有加锁,所以当Thread-0沉睡时,主线程往下执行,调用getValue方法。

    package cn.itcast_01_mythread.thread.thread;
    
    /**
     * 多个线程多个锁
     * @author HL
     *
     */
    public class MyThread2 {
    	private static int age=0;
    	
    	public static void main(String[] args) {
    		final MyThread2 m1=new MyThread2();
    		final MyThread2 m2=new MyThread2();
    		Thread t1=new Thread(new Runnable() {
    			@Override
    			public void run() {
    				m1.printNum("zs");
    			}
    		});
    		
    		Thread t2=new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				m2.printNum("lisi");
    				
    			}
    		});
    		
    		t1.start();
    		t2.start();
    	}
    	//TODO static 升级成class
    	public static synchronized void printNum(String name){
    			try {
    				if(name.equals("zs")){
    					age=18;
    					System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    					System.out.println("thread zs do something");
    					Thread.sleep(1000);
    				}else{
    					age=20;
    					System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    					System.out.println("thread lisi do something");
    				}
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		System.out.println("当前调用printNum线程是"+Thread.currentThread().getName());
    		System.out.println("name="+name+"----age="+age);
    	}
    }
    

    输出结果:

    当前调用printNum线程是Thread-0
    thread zs do something
    当前调用printNum线程是Thread-0
    name=zs----age=18
    当前调用printNum线程是Thread-1
    thread lisi do something
    当前调用printNum线程是Thread-1
    name=lisi----age=20
    

    2、线程的同步异步问题(多个线程)

    2.1、未加前

    package cn.itcast_01_mythread.thread.thread;
    /*
     * 线程的同步异步
     */
    public class Sync_Async_3 {
        public synchronized void method1(){
            try{
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(4000);
                System.out.println("线程0-------执行完毕");
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        public void method2(){
            try{
                System.out.println(Thread.currentThread().getName());
                System.out.println("线程1--------执行完毕");
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            final Sync_Async_3 sa = new Sync_Async_3() ;
            /**
             * T1线程先持有Sync_Async对象的Lock锁 , t2线程可以以异步的方式调用对象中非synchronized修饰的方法
             * 如果在method2上加入synchronized关键字,t2这个时候如果想调用synchronized关键字的方法,就需要等t1执行完毕之后才能调用,也就是同步
             * */
    
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    sa.method1();
                }
            }) ;
    
            Thread t2 = new Thread(new Runnable() {
                public void run() {
                    sa.method2();
                }
            }) ;
            t1.start();
            t2.start();
        }
    }
    

    输出结果:

    Thread-0
    Thread-1
    线程1--------执行完毕
    线程0-------执行完毕
    

    2.2、加锁之后,同步

    package cn.itcast_01_mythread.thread.thread;
    /*
     * 线程的同步异步
     */
    public class Sync_Async_3 {
        public synchronized void method1(){
            try{
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(4000);
                System.out.println("线程0-------执行完毕");
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        //TODO synchronized
        public  synchronized void method2(){
            try{
                System.out.println(Thread.currentThread().getName());
                System.out.println("线程1--------执行完毕");
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            final Sync_Async_3 sa = new Sync_Async_3() ;
            /**
             * T1线程先持有Sync_Async对象的Lock锁 , t2线程可以以异步的方式调用对象中非synchronized修饰的方法
             * 如果在method2上加入synchronized关键字,t2这个时候如果想调用synchronized关键字的方法,就需要等t1执行完毕之后才能调用,也就是同步
             * */
    
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    sa.method1();
                }
            }) ;
    
            Thread t2 = new Thread(new Runnable() {
                public void run() {
                    sa.method2();
                }
            }) ;
            t1.start();
            t2.start();
        }
    }
    

    输出结果:

    Thread-0
    线程0-------执行完毕
    Thread-1
    线程1--------执行完毕
    

    3、脏读

    3.1、不加锁(一个线程)

    当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程无法执行。

    而getValue并没有加锁,所以当Thread-0沉睡时,主线程往下执行,调用getValue方法。

    package cn.itcast_01_mythread.thread.thread;
    /*
     * 脏读
     */
    public class Dirty_read_4 {
        private String weibo_name = "angel" ;
        private String weibo_sex = "女" ;
        //synchronized
        public synchronized void setValue(String weibo_name , String weibo_sex){
            System.out.println("执行setValue方法的线程是:"+Thread.currentThread().getName());
            this.weibo_name = weibo_name ;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.weibo_sex = weibo_sex ;
            System.out.println("setValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
        }
        public  void getValue(){
            System.out.println("执行getValue方法的线程是:"+Thread.currentThread().getName());
            System.out.println("getValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
        }
    
        public static void main(String[] args) throws InterruptedException {
            final Dirty_read_4 dr = new Dirty_read_4();
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    dr.setValue("huangxiaoming" , "男");
                }
            }) ;
            t1.start();
            Thread.sleep(1000);
            dr.getValue();
        }
    }
    

    输出结果:顺序混乱

    执行setValue方法的线程是:Thread-0
    执行getValue方法的线程是:main
    getValue---------weibo_name :huangxiaoming-- weibo_sex : 女
    setValue---------weibo_name :huangxiaoming-- weibo_sex : 男
    

    3.2、加锁后(一个线程)

    当调用setValue方法的时候,执行到sleep方法,sleep是带锁沉睡。sleep在阻塞当前线程(Thread-0)的同时,并持有该对象锁(对象Dirty_read_4 dr),所以该对象的其他同步线程(getValue())无法执行。只有等到setValue执行完,getValue才会执行。

    package cn.itcast_01_mythread.thread.thread;
    /*
     * 脏读
     */
    public class Dirty_read_4 {
        private String weibo_name = "angel" ;
        private String weibo_sex = "女" ;
        //synchronized
        public synchronized void setValue(String weibo_name , String weibo_sex){
            System.out.println("执行setValue方法的线程是:"+Thread.currentThread().getName());
            this.weibo_name = weibo_name ;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.weibo_sex = weibo_sex ;
            System.out.println("setValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
        }
        //TODO synchronized
        public synchronized  void getValue(){
            System.out.println("执行getValue方法的线程是:"+Thread.currentThread().getName());
            System.out.println("getValue---------weibo_name :" + weibo_name + "-- weibo_sex : "+weibo_sex);
        }
    
        public static void main(String[] args) throws InterruptedException {
            final Dirty_read_4 dr = new Dirty_read_4();
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    dr.setValue("huangxiaoming" , "男");
                }
            }) ;
            t1.start();
            Thread.sleep(1000);
            dr.getValue();
        }
    }
    

    输出结果:

    执行setValue方法的线程是:Thread-0
    setValue---------weibo_name :huangxiaoming-- weibo_sex : 男
    执行getValue方法的线程是:main
    getValue---------weibo_name :huangxiaoming-- weibo_sex : 男
    
  • 相关阅读:
    求最大子数组和
    第四周学习进度
    四则运算3
    实用工具箱app开发日记5
    实用工具箱app开发日记4
    实用工具箱app开发日记3
    实用工具箱app开发日记2
    实用工具箱app开发日记1
    《软件需求与分析》阅读笔记
    软件需求分析--阅读笔记3
  • 原文地址:https://www.cnblogs.com/amunamuna/p/10300233.html
Copyright © 2020-2023  润新知