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();
    }
}

  

posted @ 2019-05-08 17:38  石shi  阅读(416)  评论(0编辑  收藏  举报