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

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)
{
	//线程1
	Thread t1 = new Thread(new Runnable()
	{
		@Override
		public void run()
		{
			while(true)
			{
				//调用outputer对象的output
				outputer.output("abcdefghijk");
				try
				{
					Thread.sleep(10);
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}
		}
	});
	
	//线程2
	Thread t2 = new Thread(new Runnable()
	{
		@Override
		public void run()
		{
			while(true)
			{
				//调用outputer对象的output
				outputer.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();
        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值