好久没有复习java多线程相关知识点了,在此对自己的一些思考做一个记录。
说到java多线程,最有名的就是synchronized关键字了。
一.synchronized关键字的实现原理
java程序运行时所有的对象都存储在JVM中,而在JVM中所有的对象都可以作为内置锁对象。
synchronized修饰的不论是方法还是代码块都表明其中的内容想要执行,必须先获取对象的内置锁才行。因此synchronized获取的代码块中锁定的对象不能为null。
但synchronized方法不能阻止其他线程通过普通方法(非线程安全方法)去访问修改其修饰的对象,所以我们需要将所有涉及到修改同一对象的操作都用synchronized进行修饰。
二.synchronized用法
synchronized关键字可用于修饰代码块、普通方法与静态方法;synchronized修饰代码块的时候其可以获取内置锁的对象包括this、XXX.class以及其他对象。
其中根据JVM内存原理,可以明确this与XXX.class不是一个对象。this指向的是该类通过new创建一个新对象后的映射;XXX.class等效于this.getClass(),即其指向的都是java运行时加载在栈中的类型。
三.synchronized修饰的普通方法与静态方法分别获取了什么对象的内置锁呢?
答案是synchronized修饰的普通方法获取的是等效于this的指向对象的内置锁,即新创建的对象本身;synchronized修饰的静态方法获取的是该方法所在类的内置锁,即XXX.class
四.问题三的验证代码与结果
1.普通方法
public class Test {
public static void main(String[] args) {
final Test test = new Test();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
}
private static String name = "ajajajaj";
public synchronized void say1(){
System.out.println("R1");
int miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println(Test.class + "start1");
miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println("miao1");
}
public void say2(){
System.out.println("R2");
int miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
synchronized (this) {
System.out.println(Test.class + "start2");
miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println("miao2");
}
}
}
结果:
R1
R2
class com.thread.Teststart1
R2
R1
miao1
R1
class com.thread.Teststart1
miao1
class com.thread.Teststart1
miao1
R2
class com.thread.Teststart2
R1
miao2
class com.thread.Teststart2
R2
miao2
class com.thread.Teststart2
miao2
class com.thread.Teststart2
miao2
class com.thread.Teststart1
miao1
2.静态方法
public class Test {
public static void main(String[] args) {
final Test test = new Test();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.say2();
}
}).start();
}
private static String name = "ajajajaj";
public synchronized static void say1(){
System.out.println("R1");
int miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println(Test.class + "start1");
miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println("miao1");
}
public void say2(){
System.out.println("R2");
int miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
synchronized (this.getClass()) {
System.out.println(Test.class + "start2");
miao = 0;
for(int i = 0 ;i < 10000000; ++ i){
miao = i;
}
System.out.println("miao2");
}
}
}
结果:
R1
R2
class com.thread.Teststart1
miao1
R1
class com.thread.Teststart1
miao1
class com.thread.Teststart2
miao2
R2
R1
class com.thread.Teststart1
miao1
R1
class com.thread.Teststart1
miao1
R2
class com.thread.Teststart2
miao2
R2
class com.thread.Teststart2
miao2
class com.thread.Teststart2
miao2
可以从结果中看出class com.thread.Teststart与miao的输出并未出现乱序情况,表明其确实实现了同步。
诸位有兴趣的可以自行粘贴到本地进行验证。