(二)对象以及变量的并发访问--synchronized的使用细节,用法

这篇博客包含以下几点的理解:感觉一步一步跟我来都可以看懂滴大致是按照以下思路进行书写的。黑体字可以理解为结论,1.synchronized锁的是什么?2.synchronized能够锁住所有方法吗?3.synchronized能够用来锁住一个方法之中的部分代码吗?4.synchronized能够锁住除了this以外的其他对象吗?有什么用?有什么需要注意的?---------------------...

(二)对象以及变量的并发访问--synchronized的使用细节,用法

这篇博客包含以下几点的理解:感觉一步一步跟我来都可以看懂滴

大致是按照以下思路进行书写的。黑体字可以理解为结论,

1.synchronized锁的是什么?

2.synchronized能够锁住所有方法吗?

3.synchronized能够用来锁住一个方法之中的部分代码吗?

4.synchronized能够锁住除了this以外的其他对象吗?有什么用?有什么需要注意的?

------------------------------------------------------------------------------------------正文------------------------------------------------------------------------------------------

1.synchronized锁的是什么?

首先,要明白非线程安全存在于实例变量之中,即大家都可以更改的变量,私有变量不存在线程安全问题。那么解决非线程安全问题,我们需要用用到synchronized 来给某一个方法或者对象上锁,避免交叉访问的现象出现。那么synchronized到底锁的是什么呢?

先说结论,锁的是一个对象,一个类的实例,而不是将一个方法锁起来,如果想要在加上synchronized关键字之后同步运行,那多个线程访问的必须是同一个对象,这是锁的前提。也可以理解为加上synchronized关键字之后同步访问的前提是多个线程访问的是同一个资源,相当于他们是资源共享的。

用一个例子来说明:

twoNum.java是我们的测试类,里面有带锁的addNum方法,根据目前的线程名字来赋予num不同的值,a线程为100,b线程为200

MyThread.java:是自定义线程类,用于,run方法运行twoNum对象的addNum()方法

test.java:main函数

twoNum.java:

package 第二章;public class twoNum { private int num=0; synchronized public void addNum(){  try{if(Thread.currentThread().getName().equals("a")){ num=100; System.out.println("a线程设置num的值"); Thread.sleep(2000);}else{ num=200; System.out.println("b线程设置num的值");}System.out.println(Thread.currentThread().getName() " " num);  }catch (InterruptedException e){e.printStackTrace();  } }}

MyThread.java,

package 第二章;import 第二章.twoNum;public class MyThread extends Thread {  private twoNum twonum;  public MyThread(twoNum temp){super();this.twonum=temp;  }  public void run(){super.run();twonum.addNum();  }}

test.java:

package 第二章;public class test { public static void main(String[] args){  twoNum twonum = new twoNum();  MyThread threadA = new MyThread(twonum);  threadA.setName("a");  MyThread threadB = new MyThread(twonum);  threadB.setName("b");  threadA.start();  threadB.start(); }}

运行上述代码,不出意料的,是线程安全的,并同步运行,因为我们给twonum对象的addNum方法上了锁,并且线程A,B是用一个twoNum初始化的,

更改test.java代码如下,用两个twoNum对象实例分别给A,B线程来初始化:

package 第二章;public class test { public static void main(String[] args){  twoNum twonum1 = new twoNum();  twoNum twonum2 = new twoNum();  MyThread threadA = new MyThread(twonum1);  threadA.setName("a");  MyThread threadB = new MyThread(twonum2);  threadB.setName("b");  threadA.start();  threadB.start(); }}

运行结果如下:

可以看到现在A,B两个线程执行顺序虽然是异步的,但是数据仍然是正常的。为什么呢?很明显,因为有两个twoNum对象,所以有两个对象锁,A,B线程持有不同的锁,所以他们在访问时,访问的是不同对象,那当然能异步运行了,同时也有两个num变量,从属于不同的线程,A线程并不能够更改B线程当中的num变量,所以数据也是正常的。

上面的例子看得出,锁 关键字锁的是对象,

2.synchronized能够锁住所有方法吗?

那么synchronized锁的是整个对象里面的所有方法,还是怎么样呢?

先说结论:synchronized只能够锁住一个对象当中带锁的方法,并不是全部方法。可以理解为局部同步。

这就意味着假如A线程拿到了一个对象的锁,正在访问该对象之中的一个同步方法,这时候B线程也尝试拿到同一个对象锁,如果B线程访问的是该对象当中不带锁的方法,那么久能够拿到该锁并访问,如果访问的是该对象之中带锁的方法,那么B线程无法拿到该锁,只能等A线程释放锁之后才能拿到锁。

下面是一个例子:

修改twoNum.java如下:增加了一个没有锁的方法addNum2

package 第二章;public class twoNum { private int num=0; synchronized public void addNum(){  try{if(Thread.currentThread().getName().equals("a")){ num=100; System.out.println("a线程设置num的值"); Thread.sleep(2000);}else{ num=200; System.out.println("b线程设置num的值");}System.out.println(Thread.currentThread().getName() " " num);  }catch (InterruptedException e){e.printStackTrace();  } } public void addNum2(){  try {System.out.println(Thread.currentThread().getName()"正在访问");Thread.sleep(1000);  }catch (InterruptedException e){e.printStackTrace();  }  System.out.println("访问结束"); }}

修改MyThread.java文件如下:两个线程,一个运行有锁的方法,另一个运行没有锁的

package 第二章;import 第二章.twoNum;class MyThread1 extends Thread {  private twoNum twonum;  public MyThread1(twoNum temp){super();this.twonum=temp;  }  public void run(){super.run();twonum.addNum();  }}class MyThread2 extends Thread { private twoNum twonum; 
源文地址:https://www.guoxiongfei.cn/cntech/24331.html