synchronized 基本用法

常见三种使用方式

1)普通同步方法,锁是当前实例;
2)静态同步方法,锁是当前类的Class实例,Class数据存在永久代中,是该类的一个全局锁;
3)对于同步代码块,锁是synchronized括号里配置的对象。

 

方式一   普通方法通过synchronized修饰

   1)不采用synchronized     当创建两个线程对象  线程t1  t2中采用同一个实例化类对象  调用method方法  会交异步执行  互补影响

package cn.ac.bcc.sync;
/**
 * 普通同步方法通过synchronized修饰
 * @author Administrator
 *
 */
public class PtMethod {
    
    /**
     * 1)不采用synchronized修饰
     * @param s
     */
    public  void method(String s){
        if(s.equals("a")){
            System.out.println(Thread.currentThread().getName()+": a");
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+": b");
        }
    }
    
    public static void main(String[] args) {
        //创建当前类对象实例
        final PtMethod ptMethod = new PtMethod();
        
        //创建线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod.method("a");
            }
        });
        
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod.method("b");
            }
            
        });
        
        t1.start();
        t2.start();
    }

}
View Code

 运行结果:

Thread-1: b
Thread-0: a

 2)采用synchronized   当创建两个线程对象  线程t1 t2 中采用同一个实例化对象  调用synchronized修饰的method方法  method方法中线程睡眠一秒钟  当线程t1优先抢占到method方法的执行权时由于method方法被synchronized修饰  method方法被实例化对象ptMethod对象锁锁住   当t2线程同样是ptMethod实例化对象调用当前method方法 由于两个线程t1 t2 都采用的是同一个实例化对象ptMethod 对象锁 只有t1运行完成后  t2中线程中的ptMethod对象才能调用method方法。由于method中获取当前调用线程睡眠  t2要等t1中调用的method睡眠唤醒之后执行完方法才能执行。

public class PtMethod {
    
    /**
     * 1)采用synchronized修饰
     * @param s
     */
    public synchronized  void method(String s){
        if(s.equals("a")){
            System.out.println(Thread.currentThread().getName()+": a");
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+": b");
        }
    }
    
    public static void main(String[] args) {
        //创建当前类对象实例
        final PtMethod ptMethod = new PtMethod();
        
        //创建线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod.method("a");
            }
        });
        
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod.method("b");
            }
            
        });
        
        t1.start();
        t2.start();
    }

}
View Code

 3)采用synchronized修饰   创建两个线程对象  创建当前类实例对象 ptMethod1 ptMethod2  t1线程运行ptMetod1    t2线程运行ptMethod2 对象分别调用mehod方法  运行结果如下 ,由于两个线程分别采用的是两个不同的实例对象  当两个实例对象调用method方法时  synchronized判断当前锁对象并不相同  所以里两个对象向都分别调用了method方法,而不需要等待

public class PtMethod {
    
    /**
     * 1)采用synchronized修饰
     * @param s
     */
    public synchronized  void method(String s){
        if(s.equals("a")){
            System.out.println(Thread.currentThread().getName()+": a");
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+": b");
        }
    }
    
    public static void main(String[] args) {
        //创建当前类对象实例
        final PtMethod ptMethod1 = new PtMethod();
        final PtMethod ptMethod2 = new PtMethod();
        
        //创建线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod1.method("a");
            }
        });
        
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ptMethod2.method("b");
            }
            
        });
        
        t1.start();
        t2.start();
    }

}
View Code

 

 运行结果:

Thread-0: a

Thread-1: b

二、synchronized修饰静态方法
采用synchronized  修饰的静态方法  两个线程通过不同的  类实例对象调用  这个方法  如何加锁  这是可以将该方法修改为static 方法  并synchronized修饰

public class SyncDemo {

    /**
     * 类方法  synchronized修饰  解决多个线程调用当前类不同实例采用同步锁方法
     * @param s
     */
    public static  synchronized void method(String s){
        
        if(s.equals("a")){
            System.out.println(Thread.currentThread().getName()+": a");
            
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+": b");
        }
    }
    
    public static void main(String[] args) {
        
        final SyncDemo syncDemo1 = new SyncDemo();
        final SyncDemo syncDemo2 = new SyncDemo();
        
        Thread t1 = new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo1.method("a");
            }
        });
        
        Thread t2 = new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo2.method("b");
            }});
        t1.start();
        t2.start();
    }
}
View Code

 三、同步代码块

  1)当两个并发线程同时访问一个对象的同步代码块synchronized(this),在某一时刻只有一条线程才能访问该同步代码块

public class SyncDemo1 implements Runnable {
    
    
    public static void main(String[] args) {
    
        SyncDemo1 syncDemo1 = new SyncDemo1();
        new Thread(syncDemo1,"a").start();;
        new Thread(syncDemo1,"b").start();;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println(Thread.currentThread().getName()+"执行开始run方法");
        synchronized (this) {
            System.out.println(Thread.currentThread().getName());
        }
    }

}
View Code

运行结果:  当b抢到执行权只有b线程执行完成a线程才能继续执行

b执行开始run方法
b
a执行开始run方法
a

2)当一个线程访问object对象中的synchronized(this)同步代码块时,另一个线程可以访问object对象的非同步代码块

package cn.ac.bcc.sync;

public class SyncDemo2 {

    public void method1(){
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+"线程同步代码块");
        }
    }
    
    public void method2(){
        System.out.println(Thread.currentThread().getName()+"当两个线程访问同一个object 中的方法   一个线程访问线程同步方法  另一个可以方位object对象的非线程同步方法");
    }
    
    public static void main(String[] args) {
        
        final SyncDemo2 syncDemo2 = new SyncDemo2();
        
        //创建两个线程对象
        Thread t1 = new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo2.method1();
            }
        },"t1");
        
        Thread t2 = new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo2.method2();
            }
            
        },"t2");
        
        t1.start();
        t2.start();
        
        
    }
}
View Code

3)当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

package cn.ac.bcc.sync;

public class SyncDemo2 {

    public void method1(){
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+"线程同步代码块");
            try {
                System.out.println(Thread.currentThread().getName()+"睡一会");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    public void method2(){
        
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+"访问线程同步代码块");
        }
    }
    
    public static void main(String[] args) {
        
        final SyncDemo2 syncDemo2 = new SyncDemo2();
        
        //创建两个线程对象
        Thread t1 = new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo2.method1();
            }
        },"t1");
        
        Thread t2 = new Thread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                syncDemo2.method2();
            }
            
        },"t2");
        
        t1.start();
        t2.start();
        
        
    }
}
View Code

运行结果:

t1线程同步代码块
t1睡一会

10秒后t2才能访问当前对象其他同步代码块修饰的方法

t1线程同步代码块
t1睡一会
t2访问线程同步代码块

 

posted @ 2018-07-04 17:56  liuwd  阅读(326)  评论(0编辑  收藏  举报