java线程中的synchronized同步关键字
直接po代码和截图
Person类
package com.demo.thread3;
//Person类
public class Person {
}
TestSynchronized类
package com.demo.thread3;
//测试synchronized()同步块的小括号中可以放什么?
public class TestSynchronized {
String address = "江西省赣州市于都县";
double salary = 16500.66;
public static void main(String[] args) {
// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
}
public void hi() {
int age = 6;
// synchronized(基本数据类型)会报错,连编译都通不过
// synchronized(age){
// System.out.println("测试同步块######");
// }
}
public void hi2() {
// synchronized(基本数据类型)会报错,连编译都通不过
// synchronized(salary){
// System.out.println("测试同步块------");
// }
}
public void hello() {
// synchronized(当前对象)
synchronized (this) {
System.out.println("测试同步块1");
}
}
public void hello2() {
String testName = "令狐冲";
// synchronized(字符串类型对象)
synchronized (testName) {
System.out.println("测试同步块2");
}
}
public void hello3() {
//自定义的Person类
Person person = new Person();
// synchronized(自定义类型对象)
synchronized (person) {
System.out.println("测试同步块3");
}
}
public void hello4() {
// synchronized(自定义类型对象)
synchronized (new Person()) {
System.out.println("测试同步块4");
}
}
public void hello5() {
// synchronized(字符串类型对象)
synchronized (new String("张无忌")) {
System.out.println("测试同步块5");
}
}
public void hello6() {
// synchronized(Integer类型对象)
Integer number = 666;
synchronized (number) {
System.out.println("测试同步块6");
}
}
public void hello7() {
//定义一个int数组(数组也是引用类型,即对象类型)
int[] score = { 66, 88 };
// synchronized(数组类型对象)
synchronized (score) {
System.out.println("测试同步块7");
}
}
public void hello8() {
// synchronized(类中的属性),该属性必须是引用类型
synchronized (this.address) {
System.out.println("测试同步块8");
}
}
public void hello9() {
// synchronized(类中的属性),该属性必须是引用类型
synchronized (address) {
System.out.println("测试同步块9");
}
}
}
TestSynchronized2类
package com.demo.thread3;
//测试synchronized同步块和synchronized同步方法
public class TestSynchronized2 {
private String name = "韦小宝";
private String id = "8866";
/**
* 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很
* 明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越
* 差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
*
* 同步代码块可以用更细粒度的控制锁
*/
/**
* 如果你有一个TestSynchronized2对象 你想在多线程下同时修改Name和id, 如果你两个set方
* 法都声明为同步方法,那么在同一时间只能修改name或者id. 但是这两个是可以同时修改的,所以你需要使用同
* 步代码块,将信号量分别设置成name和id.
*/
//同步代码块可以用更细粒度的控制锁,比如下面两个set方法
public void setName(String name) {
synchronized (name) {
this.name = name;
}
}
public void setId(String id) {
synchronized (id) {
this.id = id;
}
}
/**
*如果像下面的写法,在方法上加synchronized同步关键字,那么在同一时
*间只能有一个线程修改name或者id,很明显,这样做不太好,也不太合理
*所以,建议使用上面的synchronized同步块的方式
*/
public synchronized void setName2(String name) {
this.name = name;
}
public synchronized void setId2(String id) {
this.id = id;
}
/**
*如下3个方法
*synchronized(对象)同步块后面的小括号中,可以放任何对象,只要是引用类型(即对象类型)就可以,
*所以synchronized同步块比较灵活,没有局限性(同步块后面需要传递同
*步的对象,所以同步块的好处就是,可以指定更多的对象享受同步的优势),而不像同步方法那样只
*有包含相关代码的对象受益(即,同步方法写在哪个类中,哪个类的对象才能有同步的功能,所以同步方法相
*对于同步块来说,有局限性,所以,我个人建议大家使用同步块)
*/
//测试synchronized()同步块的小括号中可以放什么?
// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
public void test1() {
// synchronized(自定义类型对象)
synchronized (new Person()) {
System.out.println("测试同步块1");
}
}
public void test2() {
// synchronized(字符串类型对象)
synchronized (new String("江西省赣州市于都县")) {
System.out.println("测试同步块2");
}
}
public void test3() {
// synchronized(Integer类型对象)
Integer number = 666;
synchronized (number) {
System.out.println("测试同步块3");
}
}
// synchronized()的小括号中可以放引用类型(即对象类型),但是不能放基本数据类型
public void test4() {
int age = 12;
// synchronized(基本数据类型)会报错,连编译都通不过
// synchronized(age){
// System.out.println("测试同步块4");
// }
}
public static void main(String[] args) {
}
}
SynObj类
package com.demo.thread3;
public class SynObj {
public synchronized void methodA() {
//只要进入了methodA()函数,就意味着对象锁住了
System.out.println("methodA....." + Thread.currentThread() + " " + Thread.currentThread().getName());
try {
// sleep()方法导致了线程暂停执行指定的时间,让出cpu给其他线程,
// 但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
// 在调用sleep()方法的过程中,线程不会释放对象锁。
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是methodA()函数");
}
public void methodB() {
synchronized (this) {
System.out.println("methodB....." + Thread.currentThread() + " " + Thread.currentThread().getName());
}
}
public void methodC() {
String str = "江西省赣州市于都县";
synchronized (str) {//synchronized(str)这句话中的小括号中放的是String字符串对象
System.out.println("methodC....." + Thread.currentThread() + " " + Thread.currentThread().getName());
}
}
public void methodD() {
System.out.println("methodD....." + Thread.currentThread() + " " + Thread.currentThread().getName());
try {
// sleep()方法导致了线程暂停执行指定的时间,让出cpu给其他线程
Thread.sleep(5000);//执行这句话的时候,还没锁,也就意味着,此时其他线程可以执行同一个对象的另一个同步方法
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用同步块,可以减小线程同步的粒度,线程同步的粒度越小越好,即线程同步的代码块越小越好
/*
* 同步代码块可以用更细粒度的控制锁,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越
* 大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
*/
synchronized (this) {//执行了这句话的时候,才开始锁
System.out.println("我是methodD()函数中的synchronized同步块");
}
System.out.println("我是methodD()函数");
}
public synchronized void methodE() {
System.out.println("methodE....." + Thread.currentThread() + " " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是methodE()函数");
}
public void methodF() {
System.out.println("methodF....." + Thread.currentThread() + " " + Thread.currentThread().getName());
synchronized (this) {
System.out.println("我是methodF()函数中的synchronized同步块");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是methodF()函数");
}
public synchronized void methodG() {
System.out.println("我是一个同步方法methodG....." + Thread.currentThread() + " " + Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是methodG()函数,我是一个同步方法");
}
public synchronized void methodH() {
System.out.println("我是methodH()函数,我是一个同步方法");
}
public void methodJ() {
System.out.println("我是methodJ()函数,我是一个普通方法");
}
}
TestSyn类
package com.demo.thread3;
public class TestSyn {
/**
* 测试后,最终运行的结果是打印出如下:
* methodA.....
* methodC...
* 下面这2句话要隔几秒钟才会打印出来
* 我是methodA()函数
* methodB.....
*/
public static void main(String[] args) {
/**
* 分析运行过程如下,供大家参考:
* 启动线程1调用方法methodA后,会打印出methodA.....
* 接着会让线程1休眠5秒钟,
* 这时会调用方法methodC,注意到方法methodC这里用synchronized进行加锁,这里锁的对象是str这个字符串对象,
* 所以此时会打印出methodC.....
* 但是方法methodB则不同,是用当前对象this进行加锁,方法methodA直接在方法上加synchronized关键字,
* 显然,methodB和methodA这两个方法用的是同一把锁
* 显然,在methodA同步方法中,在调用sleep()方法的过程中,线程不会释放对象锁
* 当线程1指定的5秒钟时间到了,又会自动恢复运行状态,此时打印出我是methodA()函数,
* 当线程1的methodA()同步方法执行完毕后,此时会释放掉锁,此
* 时才会执行线程2中的methodB方法,此时打印出methodB.....
*
* 由此可知,在methodA方法上加synchronized同步关键字和在methodB方
* 法内加synchronized同步块, 这两种加锁机制用的是同一个锁对象,即当前对象
*
* 所以,最终运行的结果是
* methodA.....
* methodC...
* 下面这2句话要隔几秒钟才会打印出来
* 我是methodA()函数
* methodB.....
*/
/**
* 同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很
* 明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越
* 差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
*
* 同步代码块可以用更细粒度的控制锁
*/
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodA();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodB();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodC();
}
});
t3.start();
}
}
运行结果如下:
TestSyn2类
package com.demo.thread3;
public class TestSyn2 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodD();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodB();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodC();
}
});
t3.start();
}
}
运行结果如下:
TestSyn3类
package com.demo.thread3;
public class TestSyn3 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodF();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodB();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodC();
}
});
t3.start();
}
}
运行结果如下:
TestSyn4类
package com.demo.thread3;
public class TestSyn4 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodE();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodB();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodC();
}
});
t3.start();
}
}
运行结果:
TestSyn5类
package com.demo.thread3;
public class TestSyn5 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodG();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodH();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodJ();
}
});
t3.start();
}
}
运行结果:
TestSyn6类
package com.demo.thread3;
public class TestSyn6 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodF();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodB();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodG();
}
});
t3.start();
}
}
运行结果:
TestSyn7类
package com.demo.thread3;
public class TestSyn7 {
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodD();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodH();
}
});
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
obj.methodJ();
}
});
t3.start();
}
}
运行结果: