synchronized详解

基于synchronized本身写了一个小demo作实验,起两个线程调用一个方法,这个方法在单线程运行下能够把变量增长10000html

 

如代码写了4种synchronized方式java

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

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

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

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

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

e:没有使用synchronized,而是使用atomicInteger变量作增长线程

f:在Sint的class上,code

 

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

首先看两个线程调用一个同一个方法预期与结果不通的,只有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是同一类型),也不会产生线程安全问题,由于他们访问的是不一样的对象,因此不存在互斥问题。

相关文章
相关标签/搜索