Java基础巩固之线程的同步synchronized

来源:互联网 发布:工作证在线生成软件 编辑:程序博客网 时间:2024/06/06 05:12

Java中的synchronized关键字,可以用来修饰方法和代码块,主要是为了保证在同一时刻只有一条线程访问被修饰的代码。

synchronized分为对象级别的同步和类级别的同步。

1、当使用synchronized关键字修饰普通方法时,如果已经有一条线程访问此方法,那么其他使用同一对象调用此方法的线程,需要等待此线程执行完成后释放对象锁才能执行该方法,同时需要注意的是也无法执行当前对象中使用synchronized修饰的其他方法,但是可以执行非synchronized修饰的方法

2、当使用static synchronized关键字修饰普通方法时,如果已经有一条线程访问此方法,那么其他使用此类的任何实例化对象调用此方法的线程,需要等待此线程执行完成后释放锁才能执行该方法,同时需要注意的是也无法执行类中使用synchronized或者static synchronized修饰的其他方法,但是可以执行非synchronized修饰的方法


来一段代码,看看在没使synchronized关键字同步代码时,用两个线程访问同一资源是否会出现问题

Outputer类包含output方法,用于打印字符

class Outputer{    public synchronized void output(String str)    {        int len = str.length();        for(int i = 0; i < len; i++)        {            System.out.print(str.charAt(i));        }                System.out.println();    }}
创建两条线程,用于调用output方法
//实例化Outputer对象static Outputer outputer = new Outputer();public static void main(String[] args){//线程1Thread t1 = new Thread(new Runnable(){@Overridepublic void run(){while(true){//调用outputer对象的outputoutputer.output("abcdefghijk");try{Thread.sleep(10);}catch (InterruptedException e){e.printStackTrace();}}}});//线程2Thread t2 = new Thread(new Runnable(){@Overridepublic void run(){while(true){//调用outputer对象的outputoutputer.output("mnopqrstuvw");try{Thread.sleep(10);}catch (InterruptedException e){e.printStackTrace();}}}});t1.start();t2.start();}

在执行过程中,出现错乱的输出:



解决方法:

1、将循环输出的代码,放到synchronized同步代码块中

class Outputer{    public void output(String str)    {        String sync = "";        /*         * 1、两条线程使用的是同一个outputer对象,所以可以使用"this"         * 2、由于用一个对象中的"sync"变量只会存在一份,所以也可以使用"sync"变量来控制         */        synchronized (this/*sync*/)        {            int len = str.length();            for(int i = 0; i < len; i++)            {                System.out.print(str.charAt(i));            }                        System.out.println();        }    }}

2、用synchronized关键字修饰方法

class Outputer{    /**     * 普通方法需要类的实例化对象来调用,所以synchronized修饰的方法也只针对于同一个对象     * @param str     */    public synchronized void output(String str)    {        int len = str.length();        for(int i = 0; i < len; i++)        {            System.out.print(str.charAt(i));        }                System.out.println();    }}

以上方法只在多条线程使用同一个Outputer()对象实例调用output方法时起作用,如果每条线程都使用不同的Outputer()实例对象,则还是会出现错乱现象。


解决方法:

1、使用 static synchronized修饰方法

class Outputer{    /**     * 静态方法的调用不依赖于任何实例化对象,是类级别的方法。     * 所以synchronized控制的是类级别     * @param str     */    public static synchronized void output(String str)    {        int len = str.length();        for(int i = 0; i < len; i++)        {            System.out.print(str.charAt(i));        }                System.out.println();    }}

2、在synchronized块的参数中传入字节码对象

class Outputer{    public void output(String str)    {        /**         * 类的字节码也是一个Class对象,且在JVM中是唯一存在的         */        synchronized (Outputer.class)        {            int len = str.length();            for(int i = 0; i < len; i++)            {                System.out.print(str.charAt(i));            }                        System.out.println();        }    }}





0 0
原创粉丝点击