zoukankan      html  css  js  c++  java
  • Java线程synchronized(一)

    线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
    synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"
    public class MyThread  extends  Thread{
        
        private int count = 5 ;
        public void run() {
            count--;
            System.out.println(this.currentThread().getName() + " count = " + count);
        }
            public static void main(String[] args) {
                /**
                 * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),
                 * 		一个线程想要执行synchronized修饰的方法里的代码:
                 * 		1 尝试获得锁
                 * 		2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,
                 * 		   而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)
                 */
                MyThread myThread = new MyThread();
                Thread t1 = new Thread(myThread,"t1");
                Thread t2 = new Thread(myThread,"t2");
                Thread t3 = new Thread(myThread,"t3");
                Thread t4 = new Thread(myThread,"t4");
                Thread t5 = new Thread(myThread,"t5");
                t1.start();
                t2.start();
                t3.start();
                t4.start();
                t5.start();
            }
    }
    

      

    同步:synchronized 同步的概念就是共享锁,不是共享的资源就没必要进行同步。

    异步:asynchronized 相互之间不受到制约。

    同步的目的就是为了线程安全,需要满足两个特性:

       1.原子性

       2.可见性

    对象锁的同步和异步问题

    public class MyObject {
        public synchronized  void  method1(){
            try{
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(4000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        public void method2(){
            System.out.println(Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            final MyObject mo=new MyObject();
            /**
             * 分析:
             * t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
             * t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
             */
            Thread t1=new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.method1();
                }
            },"t1");
    
            Thread t2=new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.method2();
                }
            },"t2");
    
            t1.start();
            t2.start();
        }
    }
    

      对于对象的同步和异步方法,设计程序,一定要考虑问题的整体,不然就会出现数据不一致的情况。脏读(dirtyread)

    public class DirtyRead {
        private String username = "laoshi";
        private String password = "123";
    
        public synchronized void setValue(String username, String password){
            this.username = username;
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            this.password = password;
    
            System.out.println("setValue最终结果:username = " + username + " , password = " + password);
        }
    
        public void getValue(){
            System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password);
        }
    
    
        public static void main(String[] args) throws Exception{
    
            final DirtyRead dr = new DirtyRead();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    dr.setValue("laosun", "456");
                }
            });
            t1.start();
            Thread.sleep(1000);
    
            dr.getValue();
        }
    }
    

      

    要枷锁,一起枷锁。不加都不加,保证业务的原子性。

    synchronized锁重入:
    当一个线程得到一个对象的锁后,再次请求对象可以再次得到对象的锁
    public class SyncDubbo1 {
    
        public synchronized void method1(){
            System.out.println("method1..");
            method2();
        }
        public synchronized void method2(){
            System.out.println("method2..");
            method3();
        }
        public synchronized void method3(){
            System.out.println("method3..");
        }
    
        public static void main(String[] args) {
            final SyncDubbo1 sd = new SyncDubbo1();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    sd.method1();
                }
            });
            t1.start();
        }
    }
    

      

    public class SyncDubbo2 {
        static class Main {
            public int i = 10;
            public synchronized void operationSup(){
                try {
                    i--;
                    System.out.println("Main print i = " + i);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        static class Sub extends Main {
            public synchronized void operationSub(){
                try {
                    while(i > 0) {
                        i--;
                        System.out.println("Sub print i = " + i);
                        Thread.sleep(100);
                        this.operationSup();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    Sub sub = new Sub();
                    sub.operationSub();
                }
            });
    
            t1.start();
        }
    }
    

      synchronized异常

    public class SyncException {
        private int i = 0;
        public synchronized void operation(){
            while(true){
                try {
                    i++;
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " , i = " + i);
                    if(i == 20){
                        //Integer.parseInt("a");
                        throw new RuntimeException();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            final SyncException se = new SyncException();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    se.operation();
                }
            },"t1");
            t1.start();
        }
    }
    

      锁对象的改变问题

    public class ChangeLock {
        private String lock = "lock";
    
        private void method(){
            synchronized (lock) {
                try {
                    System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
                    lock = "change lock";
                    Thread.sleep(2000);
                    System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            final ChangeLock changeLock = new ChangeLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    changeLock.method();
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    changeLock.method();
                }
            },"t2");
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
    }
    

      死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况

    public class DeadLock implements Runnable{
        private String tag;
        private static Object lock1 = new Object();
        private static Object lock2 = new Object();
    
        public void setTag(String tag){
            this.tag = tag;
        }
    
        @Override
        public void run() {
            if(tag.equals("a")){
                synchronized (lock1) {
                    try {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock2) {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
                    }
                }
            }
            if(tag.equals("b")){
                synchronized (lock2) {
                    try {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock1) {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
                    }
                }
            }
        }
    
        public static void main(String[] args) {
    
            DeadLock d1 = new DeadLock();
            d1.setTag("a");
            DeadLock d2 = new DeadLock();
            d2.setTag("b");
    
            Thread t1 = new Thread(d1, "t1");
            Thread t2 = new Thread(d2, "t2");
    
            t1.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
    }
    

      

    同一对象属性的修改不会影响锁的情况
    public class ModifyLock {
        private String name ;
        private int age ;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public synchronized void changeAttributte(String name, int age) {
            try {
                System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 开始");
                this.setName(name);
                this.setAge(age);
    
                System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 修改对象内容为: "
                        + this.getName() + ", " + this.getAge());
    
                Thread.sleep(2000);
                System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            final ModifyLock modifyLock = new ModifyLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    modifyLock.changeAttributte("张三", 20);
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    modifyLock.changeAttributte("李四", 21);
                }
            },"t2");
    
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
    }
    使用synchronized代码块加锁,比较灵活
    public class ObjectLock {
        public void method1(){
            synchronized (this){//对象锁
                try {
                    System.out.println("do method1..");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void method2(){  //类锁
            synchronized (ObjectLock.class){
                try {
                    System.out.println("do method2..");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        private Object lock=new Object();
        public void method3(){  //任何对象锁
            synchronized (lock){
                try {
                    System.out.println("do method3..");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
    
            final ObjectLock objLock = new ObjectLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    objLock.method1();
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    objLock.method2();
                }
            });
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    objLock.method3();
                }
            });
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

      使用synchronized代码块减小锁的粒度,提高性能

    public class Optimize {
        public void doLongTimeTask(){
            try {
    
                System.out.println("当前线程开始:" + Thread.currentThread().getName() +
                        ", 正在执行一个较长时间的业务操作,其内容不需要同步");
                Thread.sleep(2000);
    
                synchronized(this){
                    System.out.println("当前线程:" + Thread.currentThread().getName() +
                            ", 执行同步代码块,对其同步变量进行操作");
                    Thread.sleep(1000);
                }
                System.out.println("当前线程结束:" + Thread.currentThread().getName() +
                        ", 执行完毕");
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            final Optimize otz = new Optimize();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    otz.doLongTimeTask();
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    otz.doLongTimeTask();
                }
            },"t2");
            t1.start();
            t2.start();
        }
    }
    

      

    synchronized代码块对字符串的锁,注意String常量池的缓存功能
    public class StringLock {
         public void method(){
             synchronized ("字符串常量") {
                 try {
                     while(true){
                         System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
                         Thread.sleep(1000);
                         System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
                     }
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }
        public static void main(String[] args) {
            final StringLock stringLock = new StringLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    stringLock.method();
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    stringLock.method();
                }
            },"t2");
    
            t1.start();
            t2.start();
        }
    }
    

      

  • 相关阅读:
    ASP.NET Core -- 安装版
    基础知识系列☞各版本下IIS请求处理过程区别
    基础知识系列☞IList ←vs→ List
    005杰信-factory删除数据
    004杰信-关于formSubmit('factorycreate.action','_self')路径的疑惑
    23SpringMvc_各种参数绑定方式-就是<input那种
    003杰信-在jsp页面输入数据,然后在oracle数据库中插入factory数据,当字段允许为空时要特殊处理
    spring+springmvc+mybatis+maven整合
    22SpringMvc_jsp页面上的数据传递到控制器的说明
    002Jsp的内置对象
  • 原文地址:https://www.cnblogs.com/sunliyuan/p/10833316.html
Copyright © 2011-2022 走看看