synchronized详解

基于synchronized自己写了一个小demo做实验,起两个线程调用一个方法,这个方法在单线程运行下可以把变量增加10000

如代码写了4种synchronized方式

a:在方法上,控制方法的访问

b:在对象上,控制对象的访问

c:在修改的包装类ia上,预期控制ia的修改

d:在对象sint上,控制stest对象的访问

d:在对象sint上,控制stest对象的访问

e:没有使用synchronized,而是使用atomicInteger变量做增加

f:在Sint的class上,

成功达到预期的组合有 aa,bb,dd,ee,ab

首先看两个线程调用一个同一个方法预期与结果不通的,只有c方法,c和d方法不同在于,d是synchronized了一个普通对象,c是synchronized了一个包装类,发现包装类没有+1类似的方法,应该和包装类底层相关,留作问题

不同的方法组合只有ab,dd1可以,因为ab临界资源可以说有重合,如果a先执行,线程ta获取了sTest的锁,b就获取sTest的锁失败,只有等a执行结束,反之同理

d和d1都是都要获取sint对象锁,锁是临界资源,ta,tb线程谁先获取了sint对象锁执行完成,第二个线程才能执行


stest和stest1并发执行d时,输出不是预期的,因为sint是在stest内生成的,tatb线程锁住的不同对象,并发互不干扰的执行

synchronized对象时,必须是同一个对象的锁,加上

Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint
这段代码,stest和stest1并发执行后结果是预期的,因为同一时间只有一个线程可以获取到sint的锁



Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint

stest和stest1并发执行f方法时,结果就是预期的
stest执行f,stest1执行d,结果不是预期的,两个线程获取的锁不同,互不干扰的并发执行


以下是来自博客http://www.cnblogs.com/highriver/archive/2011/12/18/2291965.html

synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待.class与this做为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例.

synchronized(class)
synchronized(this)
->线程各自获取monitor,不会有等待.
synchronized(this)
synchronized(this)
->如果不同线程监视同一个实例对象,就会等待,如果不同的实例,不会等待.
synchronized(class)
synchronized(class)
->如果不同线程监视同一个实例或者不同的实例对象,都会等待.

package test.synchronize_wait_notify_lock.synchronizedp;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @Auther: zhangyahui
* @Date: 2019/1/31 15:41
* @Description:
*/
public class SynchronizedTest {

public static void main(String[] args) throws InterruptedException {

STest sTest = new STest();

STest sTest1 = new STest();


new Thread() {
public void run() {
sTest.d("ta");
}

;
}.start();

new Thread() {
public void run() {
sTest.d1("tb");
}

;
}.start();


/*Sint sint = new Sint();
sTest.sint = sint;
sTest1.sint = sint;

new Thread() {
public void run() {
sTest.d("ta");
}

;
}.start();

new Thread() {
public void run() {
sTest1.d1("tb1");
}

;
}.start();*/

}
}

class Sint {
private int i = 0;
private int m = 0;

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public int getM() {
return m;
}

public void setM(int m) {
this.m = m;
}
}

class STest {
static Integer ia = 0;
AtomicInteger ai = new AtomicInteger(0);
static final int count = 10000;
Sint sint = new Sint();


public synchronized void a(String s) {
/*synchronized(ia)*/
{
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}

public void b(String s) {
synchronized (this) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* c方法没有预期的效果,结果很乱,应该是包装类本身的问题
* 最后的结果也大概率不是20000
*/
public void c(String s) {
synchronized (ia) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* d方法的输出和预期一致,锁住了sint对象的操作
*/
public void d(String s) {
synchronized (sint) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setI(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* d方法的输出和预期一致,锁住了sint对象的操作
*/
public void d1(String s) {
synchronized (sint) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setM(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

/*
* 使用了原子int,先结束的线程值大概率不是10000而是一个接近20000的数字
* 但是最后结束的线程输出的值必然是20000,原子int自身维护了资源的访问
*/
public void e(String s) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ai.incrementAndGet();
i++;
}
System.out.println("this is " + s + " " + ai.get() + " " + System.currentTimeMillis());
}
}

public void f(String s) {
synchronized (Sint.class) {
System.out.println("jinru " + s);
int i = 0;
while (i < count) {
ia++;
sint.setM(ia);
i++;
}
System.out.println("this is " + s + " " + ia + " " + System.currentTimeMillis());
}
}

一个线程获取了对象的锁以后,可以访问该对象所有的synchronized方法或方法块

以下是来自海子博客的一些内容https://www.cnblogs.com/dolphin0520/p/3923737.html

synchronized方法。

  1)当一个线程正在访问一个对象的synchronized方法,那么其他线程不能访问该对象的其他synchronized方法。这个原因很简单,因为一个对象只有一把锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,所以无法访问该对象的其他synchronized方法。

  2)当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法。这个原因很简单,访问非synchronized方法不需要获得该对象的锁,假如一个方法没用synchronized关键字修饰,说明它不会使用到临界资源,那么其他线程是可以访问这个方法的,

  3)如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象object2的synchronized方法fun1,即使object1和object2是同一类型),也不会产生线程安全问题,因为他们访问的是不同的对象,所以不存在互斥问题。

原文地址:https://www.cnblogs.com/heroinss/p/10342899.html