1.为何要使用synchronizedjava
在并发编程中存在线程安全问题,主要缘由有:1.存在共享数据 2.多线程共同操做共享数据。关键字synchronized能够保证在同一时刻,只有一个线程能够执行某个方法或某个代码块,同时synchronized能够保证一个线程的变化可见(可见性),便可以代替volatile。编程
案例安全
package com.yxl.demo.ThreadTest;多线程
public class test5 {并发
public static void main(String[] args) {ide
TestDemo thread = new TestDemo();性能
Thread t1 = new Thread(thread,"窗口一");优化
Thread t2 = new Thread(thread,"窗口二");spa
t1.start();线程
t2.start();
}
}
class TestDemo implements Runnable{
//共享的火车票变量
private volatile int count = 100;
//重寫run方法
@Override
public void run() {
while (count > 0){
try {
Thread.sleep(50);
}catch (Exception e){
e.getMessage();
}
sale();
}
}
public void sale(){
if(count > 0){
System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
count--;
}
}
}
会出现火车票卖重复的问题,
2.实现原理
synchronized能够保证方法或者代码块在运行时,同一时刻只有一个方法能够进入到临界区,同时它还能够保证共享变量的内存可见性
Synchronized的做用主要有三个:
原子性:确保线程互斥的访问同步代码;
可见性:保证共享变量的修改可以及时可见,实际上是经过Java内存模型中的 “对一个变量unlock操做以前,必需要同步到主内存中;若是对一个变量进行lock操做,则将会清空工做内存中此变量的值,在执行引擎使用此变量前,须要从新从主内存中load操做或assign操做初始化变量值” 来保证的;
有序性:有效解决重排序问题
3.synchronized的三种应用方式
Java中每个对象均可以做为锁,这是synchronized实现同步的基础:
普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要得到当前实例的锁
public synchronized void sale(){
if(count > 0){
System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
count--;
}
}
静态同步方法**,锁是当前类的class对象 ,进入同步代码前要得到当前类对象的锁**
public static synchronized void sale(){
if(count > 0){
System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
count--;
}
}
同步代码块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要得到给定对象的锁。
private Object object =new Object();
public void sale(){
synchronized (object){
if(count > 0){
System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
count--;
}
}
}
synchronized jdk版本
在jdk1.6以前,synchronized是很是重量级的,由于它会无时无刻进行锁住对象,而不考虑到程序实际的竞争状况,大多数程序在都是进行交替执行,也就是说不存在资源的竞争,若是没有竞争,可是加锁,加锁和解锁是很是耗费性能的,(重量级)由于线程之间的切换以及线程从内核态到用户态的时间是耗费性能的。
在jdk1.6以后,sun公司对synchronized进行了大幅度的优化,如今采用偏向锁+(轻量级锁+cas)+重量级,之间经过锁碰撞进行切换。
后面对于锁新出文章进行讲解
synchronized的可重入性
从互斥锁的设计上来讲,当一个线程试图操做一个由其余线程持有的对象锁的临界资源时,将会处于阻塞状态,但当一个线程再次请求本身持有对象锁的临界资源时,这种状况属于重入锁,请求将会成功,在java中synchronized是基于原子性的内部锁机制,是可重入的,所以在一个线程调用synchronized方法的同时在其方法体内部调用该对象另外一个synchronized方法,也就是说一个线程获得一个对象锁后再次请求该对象锁,是容许的,这就是synchronized的可重入性