并发
定义
synchronized方法是java中常用的关键字,属于JVM层面,java的内置锁,Java中的每一个对象都可以作为锁,当对象被synchronized锁住之后,此对象当前是被该锁和该线程独占。
应用
分为修饰方法和修饰代码块两大类:具体如下
- 4种用法:
- 修饰实例方法
- 修饰静态方法
- 同步实例方法中的代码块
- 同步静态方法中的代码块
- 修饰实例方法
public synchronized void addOne(){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
num++;
System.out.println(this.getId()+" "+num+" "+System.currentTimeMillis());
}
当修饰实例方法时,锁住的是调用该方法的当前对象,即:
Thread thread1 = new ThreadTest();
Thread thread2 = new ThreadTest();
thread1和thread2在同一时刻调用是不会产生冲突的,但是thread1和thread2自身内部是会相互竞争的。例,多个线程不能同时调用thread1.addOne()方法。
- 修饰静态方法
public static synchronized void addTwo(){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
count += 2;
System.out.println(" "+count+" "+System.currentTimeMillis());
}
锁住的是当前这个类的Class对象,即:
当调动 addTwo()方法时,将产生竞争。不论实例对象是什么
- 修饰实例方法中的代码块
public void addThree(){
//使用了“this”,即为调用add方法的实例本身。
synchronized (this){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
number += 3;
}
System.out.println(" "+number+" "+System.currentTimeMillis());
}
重点关注synchronized (this)括号里面。this指定是引用的当前对象,效果和修饰实例方法一致。当()里面是 当前类的class对象时SynchronizedTest.class,效果和修饰静态方法一致。
- 修饰静态方法中的代码块
public static void addFour(){
synchronized (SynchronizedTest.class){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
counter += 4;
}
System.out.println(" "+counter+" "+System.currentTimeMillis());
}
当静态方法时,()里面只能是当前类的class对象 SynchronizedTest.class,效果和修饰静态方法一致。
synchronized使用的两个细节问题
- synchronized锁是可重入锁
- 父子类方法的锁可以重入
- 同一个对象的两个方法,也可以重入
public class ReentrantSynchronized extends Father {
/**
* sychronized 重写父类的方法,锁也可以重入
*/
@Override
public synchronized void doSomeThing() {
super.doSomeThing();
System.out.println(this.getClass() + " -- " + Thread.currentThread().getId() + " -- " + Thread.currentThread().getName());
System.out.println("ReentrantSynchronized child doSomeThing");
}
/**
* sychronized 同一个对象中的两个方法,也可以重入
*/
public synchronized void doOneThing() {
System.out.println(this.getClass() + " -- " + Thread.currentThread().getId() + " -- " + Thread.currentThread().getName());
System.out.println("ReentrantSynchronized child doOneThing");
doAnotherThing();
}
public synchronized void doAnotherThing() {
System.out.println(this.getClass() + " -- " + Thread.currentThread().getId() + " -- " + Thread.currentThread().getName());
System.out.println("ReentrantSynchronized child doAnotherThing");
}
public static void main(String[] args) {
ReentrantSynchronized reentrantSynchronized = new ReentrantSynchronized();
reentrantSynchronized.doSomeThing();
reentrantSynchronized.doOneThing();
}
}
class Father {
public synchronized void doSomeThing() {
System.out.println(this.getClass() + " -- " + Thread.currentThread().getId() + " -- " + Thread.currentThread().getName());
System.out.println("father doSomeThing()");
}
}
- synchronized锁是自动锁,当抛出异常时,会自动释放锁
/**
* 当异常被即时处理掉,未抛出synchronized的修饰区,不会释放锁
*/
public synchronized void doOneThing() {
int i = 0;
while (true) {
i++;
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("now,the i is:" + i);
try {
if (i == 10) {
//故意让它抛出异常
Integer.parseInt("a");
}
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
/**
* 异常抛出synchronized的修饰区,会释放锁
*/
public synchronized void doTwoThing() {
int j = -100;
while (true) {
j--;
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("yes boy,the j is:" + j);
if (j == -110) {
//故意让它抛出异常
Integer.parseInt("a");
}
}
}