java多线程编程之synchronized
2018-06-18 03:50:22来源:未知 阅读 ()
synchronized是用来解决多线程情况下的线程安全问题的,它可以修饰方法也可以修饰语句块 ,
那么什么情况下是线程安全和线程不安全呢 ?
方法内的变量是线程安全的 , 类的实例变量是非线程安全的
首先来看一个非线程安全的例子
public class HasSefPrivateNum { private int num; public void addNum(String userName) throws InterruptedException{ if("a".equals(userName)){ num=100; System.out.println("a set over"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over"); } System.out.println("num="+num); } } public class ThreadA extends Thread { private HasSefPrivateNum numRef; public ThreadA(HasSefPrivateNum numRef) { this.numRef = numRef; } @Override public void run() { super.run(); try { numRef.addNum("a"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class ThreadB extends Thread { private HasSefPrivateNum numRef; public ThreadB(HasSefPrivateNum numRef) { this.numRef = numRef; } @Override public void run() { super.run(); try { numRef.addNum("b"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class Main { public static void main(String[] args) { HasSefPrivateNum numRef = new HasSefPrivateNum(); ThreadA t1 = new ThreadA(numRef); t1.start(); ThreadB t2 = new ThreadB(numRef); t2.start(); } }
结果如下,出现非线程安全的问题
a set over b set over num=200 num=200
此时synchronized派上用场了,只要在addNum方法上synchronized,就能避免非线程安全问题
public class HasSefPrivateNum { private int num; public synchronized void addNum(String userName) throws InterruptedException{ if("a".equals(userName)){ num=100; System.out.println("a set over"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over"); } System.out.println("num="+num); } }
结果如下:
a set over num=100 b set over num=200
那么synchronized是怎么实现同步的呢
1. synchronized用在实例方法上那么它是持有对象锁,而不是把一段代码或方法当作锁,所以必须使用同一个对象当作锁才能达到同步的效果;
2. synchronized用在静态方法上那么它是对当前java文件对应的class类持锁。
首先看下synchronized修饰实例方法
public class Main { public static void main(String[] args) { HasSefPrivateNum numRef1 = new HasSefPrivateNum(); HasSefPrivateNum numRef2 = new HasSefPrivateNum(); ThreadA t1 = new ThreadA(numRef1); t1.start(); ThreadB t2 = new ThreadB(numRef2); t2.start(); } }
结果如下,没有发生同步,因为两个线程拥有两个不同对象的锁
a set over b set over num=200 num=100
synchronized解决脏读问题
public class PublicVar { private String username="A"; private String password="AA"; public synchronized void setValue(String username,String password){ try { this.username = username; Thread.sleep(5000); this.password = password; System.out.println("setValue method thread name=" + Thread.currentThread().getName() +"username:"+username+",password:"+password); } catch (InterruptedException e) { e.printStackTrace(); } } public void getValue(){ System.out.println("getValue method thread name=" + Thread.currentThread().getName() +"username:"+username+",password:"+password); } } public class ThreadA extends Thread { private PublicVar publicVar; public ThreadA(PublicVar publicVar) { this.publicVar = publicVar; } @Override public void run() { super.run(); publicVar.setValue("B", "BB"); } } public class Main { public static void main(String[] args) throws InterruptedException { PublicVar publicVar = new PublicVar(); ThreadA t1 = new ThreadA(publicVar); t1.start(); Thread.sleep(2000); publicVar.getValue(); } }
结果如下,get方法出现脏读的情况,原因是getValue方法不是同步方法,只需将getValue方法变成同步方法后就可以解决这个问题
getValue method thread name=mainusername:B,password:AA
setValue method thread name=Thread-0username:B,password:BB
对同步方法总结:
1. synchronized方法是持有对象锁,对相同的对象的synchronized方法会进行同步执行
2. 对于同一个对象锁内不同的synchronized方法持有同一个锁,即A线程调用了synchronized方法X,那么其他线程就不能调用其他的synchronized方法,直到synchronized方法x执行完后,但是可以调用其他非synchronized方法
3.synchronized方法支持锁重入,自己可以再次获得自己的内部锁,即当一个线程获得synchronized方法执行权后,在该方法内能调用该对象其他synchronized方法,如果不能重入,将会造成死锁。
4. synchronized方法出现异常,锁自动释放。
5. synchronized方法不具有继承性
使用同步代码块实现同步
synchronized的另一种用法就是同步代码块,和synchronized方法相比,它有两个有点
1. 它可以只针对方法内需要同步的代码进行同步,缩小同步范围,提高效率。
2. 它可以在同一个类中针对不同对象进行同步,提高效率。
public class Task { private String getData1; private String getdate2; public void doLongTimeTask(){ try { System.out.println("begin task"); Thread.sleep(3000); String privateGetData1 = "返回值1 thread name="+Thread.currentThread().getName(); String privateGetData2 = "返回值2 thread name="+Thread.currentThread().getName(); synchronized (this) { getData1 = privateGetData1; getdate2 = privateGetData2; } System.out.println(getData1); System.out.println(getdate2); System.out.println("end task"); } catch (InterruptedException e) { e.printStackTrace(); } } } public class ThreadA extends Thread { private Task task; public ThreadA(Task task) { this.task = task; } @Override public void run() { super.run(); task.doLongTimeTask(); } } public class ThreadB extends Thread { private Task task; public ThreadB(Task task) { this.task = task; } @Override public void run() { super.run(); task.doLongTimeTask(); } } public class Main { public static void main(String[] args) throws InterruptedException { Task task = new Task(); ThreadA t1 = new ThreadA(task); t1.start(); ThreadB t2 = new ThreadB(task); t2.start(); } }
测试结果:当一个线程访问object的同步代码块时,另一个线程可以访问该object的非同步代码块。
begin task begin task 返回值1 thread name=Thread-0 返回值2 thread name=Thread-1 返回值1 thread name=Thread-1 返回值2 thread name=Thread-1 end task end task
另外synchronized(this)是锁定当前对象的,故和synchronized方法有相同的作用
1. synchronized同步方法
1)对其他synchronized同步方法或者synchronized(this)同步代码块调用呈现阻塞状态
2)同一时间内只有一个线程可以执行synchronized同步方法中的代码
2.synchronized(this)同步代码块
1)对其他synchronized同步方法或者synchronized(this)同步代码块调用呈现阻塞状态
2)同一时间内只有一个线程可以执行synchronized(this)同步方法中的代码
将任意对象作为对象监视器
public class Service { public void test(LockObject object){ synchronized (object) { try { System.out.println("getLock time="+System.currentTimeMillis()+"thread name="+Thread.currentThread().getName()); Thread.sleep(3000); System.out.println("releaseLock time="+System.currentTimeMillis()+"thread name="+Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class ThreadA extends Thread { private Service service; private LockObject object; public ThreadA(Service service,LockObject object) { this.service = service; this.object = object; } @Override public void run() { super.run(); service.test(object); } } public class ThreadB extends Thread { private Service service; private LockObject object; public ThreadB(Service service,LockObject object) { this.service = service; this.object = object; } @Override public void run() { super.run(); service.test(object); } } public class Main { public static void main(String[] args) throws InterruptedException { Service service = new Service(); LockObject object = new LockObject(); ThreadA t1 = new ThreadA(service,object); t1.start(); ThreadB t2 = new ThreadB(service,object); t2.start(); } }
测试结果:同步调用,原因是使用了同一个对象监视器
getLock time=1516085547986thread name=Thread-0 releaseLock time=1516085550987thread name=Thread-0 getLock time=1516085550987thread name=Thread-1 releaseLock time=1516085553987thread name=Thread-1
如果不使用同一个对象监视器,则会出现异步的情况
public class Main { public static void main(String[] args) throws InterruptedException { Service service = new Service(); LockObject object1 = new LockObject(); LockObject object2 = new LockObject(); ThreadA t1 = new ThreadA(service,object1); t1.start(); ThreadB t2 = new ThreadB(service,object2); t2.start(); } }
getLock time=1516085648021thread name=Thread-0 getLock time=1516085648021thread name=Thread-1 releaseLock time=1516085651021thread name=Thread-0 releaseLock time=1516085651022thread name=Thread-1
最后要理解synchronized,其实最主要的是理解synchronized方法和synchronized代码块使用的是什么对象监视器,它们是通过锁定对象监视器来实现同步功能的
1. synchronized同步实例方法和synchronized(this)的对象监视器是对象,它将持有对象锁
2. synchronized同步静态实例方法和synchronized(class)的对象监视器是class文件,它将持有Class锁
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Linux入门
下一篇:Spring 事务管理
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash