菜鸟原创,转载注明出处:https://blog.csdn.net/yin18827152962/article/details/82780078
我们都知道sychronized对方法锁调用时候是对对象加锁,这样当线程再次使用对象的加锁资源就不需要重新获取锁,这种机制被称为可重入.(个人学习记录,如有问题望大神指正)
案例代码:
package synchronize;
import java.util.concurrent.TimeUnit;
class SynResource {
private Boolean synLock = new Boolean(false);
public void test(Thread _this) {
System.out.println("test");
run(_this);
}
synchronized public void test1(Thread _this) {
System.out.println("test1");
run(_this);
}
synchronized public void test2(Thread _this) {
System.out.println("test2");
run(_this);
}
public void testBlockString(Thread _this) {
synchronized (String.class) {
System.out.println("testBlockString");
run(_this);
}
}
public void testBlockDouble(Thread _this) {
synchronized (Double.class) {
System.out.println("testBlockDouble");
run(_this);
}
}
public void testBlockComm(Thread _this) {
synchronized (synLock) {
System.out.println("testBlockComm");
run(_this);
}
}
public void run(Thread _this){
while (true) {
try {
Thread.sleep(TimeUnit.SECONDS.toSeconds(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread name = "+_this.currentThread().getName()+" methodName = "+((ThreadTest)_this).methodName+" 该线程不会结束!");
}
}
}
class ThreadTest extends Thread {
//由jvm保证ThreadTest中syn是单例,保证它是个临界资源
private static SynResource syn = new SynResource();
String methodName = "";
public ThreadTest(String methodName){
this.methodName = methodName;
}
@Override
public void run() {
switch (methodName) {
case "test1":
syn.test1(this);
break;
case "test2":
syn.test2(this);
break;
case "test":
syn.test(this);
break;
case "testBlockString":
syn.testBlockString(this);
break;
case "testBlockDouble":
syn.testBlockString(this);
break;
case "testBlockComm":
syn.testBlockComm(this);
break;
default:
break;
}
}
}
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("test1");
ThreadTest tt2 = new ThreadTest("test");
//开启线程
tt1.start();
tt2.start();
}
}
1.调用未加锁的代码线程不会阻塞
代码调用:
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("test");
ThreadTest tt2 = new ThreadTest("test");
//开启线程
tt1.start();
tt2.start();
}
}
输出结果:
结论:两个线程可以安然无恙执行(很正常,简直废话)
2.调用加方法锁和不加方法锁的资源
代码调用:
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("test1");
ThreadTest tt2 = new ThreadTest("test");
//开启线程
tt1.start();
tt2.start();
}
}
输出结果:
结论:方法锁锁定对象后,只会对需要同步的方法加锁,需要同步的方法可以正常的被执行,即虽然锁了对象,但是不是对对象所有的资源进行加锁,废话一句,所以成员的私有化就很有必要,可以更好保证准确同步.
3.调用两个不同的同步方法
代码调用:
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("test1");
ThreadTest tt2 = new ThreadTest("test2");
//开启线程
tt1.start();
tt2.start();
}
}
输出结果:
结论:方法锁锁定是对象(及该类的对象,强调这点将有利于理解后面的块级的对象加锁),即只要调用了一个同步方法,其他线程(!!!!,自己线程是可以重入调用其他同步方法,不需要重新获取锁)将不能调用任何同步方法
1.块级锁和普通方法不会产生竞争(测试略)
2.锁同一个对象会产生竞争,很容易理解
代码调用:
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("testBlockDouble");
ThreadTest tt2 = new ThreadTest("testBlockDouble");
//开启线程
tt1.start();
tt2.start();
}
}
输出结果:
结论:对象调用使用同一个对象锁会产生阻塞,不阻塞才怪,但是这里还不能开出来,块级锁锁的不是当前被调用方法的对象
3.锁不同对象
代码调用:
public class SynTest {
public static void main(String[] args) {
ThreadTest tt1 = new ThreadTest("testBlockDouble");
ThreadTest tt2 = new ThreadTest("testBlockString");
//开启线程
tt1.start();
tt2.start();
}
}
输出结果:
结论:其实块级锁锁的已经不是当对象,而是我们synchronized()括号中的对象(简直就是废话一样),仅仅从实现讲,我们完全可以使用这种方法让几个相关联的方法使用通另一对象,然后一起加锁,对另一类使用另一个对象进行加锁,不知道又没有这样的需求,我也就是自己瞎想的
4.调用new出来的公共对象, 和使用同一个class对象一样,不再啰嗦了
最后瞎总结:看似方法锁和块级锁一个是锁对象,一个是锁区域,其实二者十一摸一样的,都是锁对象的,我们完全可以理解为方法锁的synchronized后面虚拟机自动添加了(this)部分,所以我们可以这样来看同步问题分为三个部分:
线程
资源
钥匙(就是我们加锁使用的对象)
本文章表精髓所在:那个线程抢到了要钥匙就可以执行哪些代码(非同步的都可以执行),线程拥有了钥匙,该钥匙对象也就也会被加锁,不能被其他线程调用同步方.即此时资源和钥匙都被线程锁定,然而外界线程往往不需要改钥匙对象,使用synchronized方法同步方式,我们的资源对象和钥匙对象就是同一个对象(我感觉我这样理解很对,也很有新意)
修改代码测试,重新粘贴实例代码全部:
package synchronize;
import java.util.concurrent.TimeUnit;
class YaoShi {
synchronized public void test1() {
String str = "钥匙中的同步方法是否会被同步?";
run(str);
}
public void test2() {
String str = "这是钥匙中的非同步方法";
run(str);
}
public void run(String str) {
while (true) {
try {
Thread.sleep(TimeUnit.SECONDS.toSeconds(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str);
}
}
}
class SynResource {
// 本程序调用中SynResource是单例的,所以synLock
private static YaoShi synLock = new YaoShi();
public static YaoShi getSynLock(){
return synLock;
}
public void test(Thread _this) {
System.out.println("test");
run(_this);
}
synchronized public void test1(Thread _this) {
System.out.println("test1");
run(_this);
}
synchronized public void test2(Thread _this) {
System.out.println("test2");
run(_this);
}
public void testBlockString(Thread _this) {
synchronized (String.class) {
System.out.println("testBlockString");
run(_this);
}
}
public void testBlockDouble(Thread _this) {
synchronized (Double.class) {
System.out.println("testBlockDouble");
run(_this);
}
}
public void testBlockComm(Thread _this) {
synchronized (synLock) {
System.out.println("testBlockComm");
run(_this);
}
}
public void run(Thread _this) {
while (true) {
try {
Thread.sleep(TimeUnit.SECONDS.toSeconds(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread name = " + _this.currentThread().getName() + " methodName = "
+ ((ThreadTest) _this).methodName + " 该线程不会结束!");
}
}
public void testOtherObj(ThreadTest _this) {
// 被加锁的对象当成了钥匙
synchronized (synLock) {
System.out.println("testOtherObj");
run(_this);
}
}
}
class ThreadTest extends Thread {
// 由jvm保证ThreadTest中syn是单例,保证它是个临界资源
private static SynResource syn = new SynResource();
String methodName = "";
public ThreadTest(String methodName) {
this.methodName = methodName;
}
@Override
public void run() {
switch (methodName) {
case "test1":
syn.test1(this);
break;
case "test2":
syn.test2(this);
break;
case "test":
syn.test(this);
break;
case "testBlockString":
syn.testBlockString(this);
break;
case "testBlockDouble":
syn.testBlockDouble(this);
break;
case "testBlockComm":
syn.testBlockComm(this);
break;
case "testOtherObj":
syn.testOtherObj(this);
break;
default:
break;
}
}
public static SynResource getSyn(){
return syn;
}
}
public class SynTest {
public static void main(String[] args) throws InterruptedException {
ThreadTest tt1 = new ThreadTest("testOtherObj");//试图通过这种方法获取钥匙
Thread t = new Thread(new Runnable() {
@Override
public void run() {
ThreadTest.getSyn().getSynLock().test1();//调用钥匙.看看是否阻塞
//new YaoShi().test1();//注意这是新创建的要是,不是加锁的钥匙
}
});
// 开启线程
t.start();
Thread.sleep(1000);
tt1.start();
}
}
结果:要是代码被资源代码阻塞
如有问题,望大神批评指正
转载注明出处:https://blog.csdn.net/yin18827152962/article/details/82780078