synchronized修饰方法static方法this.classobj的代码示例
Posted zhangjin1120
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了synchronized修饰方法static方法this.classobj的代码示例相关的知识,希望对你有一定的参考价值。
对象锁
一、非静态方法,方法头部加入synchronized关键字,例如:public synchronized void printC() {...}
。不同线程访问同一个对象的该方法时,会产生互斥。在jdk中,StringBuffer的append()方法就属于这种类型。
public class PrintTool {
public synchronized void printC() {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" " + Thread.currentThread().getName() + "获得锁");
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "释放锁");
}
}
public class MyThread extends Thread {
PrintTool pt;
public MyThread(PrintTool pt, String name) {
super(name);
this.pt = pt;
}
@Override
public void run() {
this.pt.printC();
}
}
public class SyncTest {
public static void main(String[] args) {
PrintTool pt = new PrintTool();
for (int i = 0; i < 5; i++) {
new MyThread(pt, "t" + i).start();
}
}
}
运行结果:
可以看到,t0最先获得锁,后面的每一个线程,只能等待上一个线程释放锁之后,才能执行这个方法。
二、在非static方法的方法体中,加入synchronized(obj){...}
代码块。拥有同一个指定对象obj的多个线程,如果同时执行这段代码块,会产生互斥。这种写法,常见于自定义线程中,多个线程同时修改一个对象。经典的多线程卖票就是这种情况。
public class PrintTool {
public void printC() {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" " + Thread.currentThread().getName() + "获得锁");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "释放锁");
}
}
public class SyncTest {
public static void main(String[] args) {
PrintTool pt = new PrintTool();
for (int i = 1; i <=3; i++) {
new Thread(new Runnable(){
@Override
public void run() {
synchronized (pt) {
pt.printC();
}
}
}, "t" + i).start();
}
}
}
运行结果:
每隔两秒,会有一个线程获得锁。而不是t1,t2,t3同时进入方法。
对象锁必须是同一个对象,才起作用。如果是不同对象,就无效。把上面的代码SyncTest修改如下,看看结果:
public class SyncTest {
public static void main(String[] args) {
for (int i = 1; i <=3; i++) {
new Thread(new Runnable(){
@Override
public void run() {
PrintTool pt = new PrintTool();
synchronized (pt) {
pt.printC();
}
}
}, "t" + i).start();
}
}
}
可以看到,3个线程同时获得了三个不同的锁,2秒后,又同时释放。synchronized就失效了。
三、在一个普通类(线程类除外)的非static方法的方法体中,使用synchronized(this){...}
代码块。拥有该普通类的同一个对象的多个线程,同时访问这个方法中的同步代码块时,会产生互斥。这种写法的场景和第二种有些不同,这种写法,经常是用于多个线程只修改同一个的对象的某一个属性,其他属性不用考虑多线程的情况,synchronized使用在同步类的内部,而不是其他类和线程的run方法中。
public class PrintTool {
public void printC() {
synchronized (this) {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "进入同步代码块");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "释放锁");
}
}
}
public class SyncTest {
public static void main(String[] args) {
PrintTool pt = new PrintTool();
for (int i = 1; i <=3; i++) {
new Thread(new Runnable(){
@Override
public void run() {
pt.printC();
}
}, "t" + i).start();
}
}
}
运行结果:
后面的线程等待前一个线程释放锁后,才能执行同步代码。
如果是不同对象,synchronized就会失效。SyncTest代码修改如下:
public class SyncTest {
public static void main(String[] args) {
for (int i = 1; i <=3; i++) {
new Thread(new Runnable(){
@Override
public void run() {
PrintTool pt = new PrintTool();
pt.printC();
}
}, "t" + i).start();
}
}
}
从结果看出,同步失效了。原因是三个线程拥有三个不同的对象,拥有三个不同的锁。
类锁
先看看,在不使用synchronized关键字的情况下,多个线程同时执行一个类的static方法,会出现什么情况。
public class PrintTool {
public static void printStaticNormal() {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" " + Thread.currentThread().getName() + "开始执行");
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "结束执行");
}
}
public class SyncTest {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Runnable(){
@Override
public void run() {
PrintTool.printStaticNormal();
}
}, "t" + i).start();
}
}
}
运行结果:
可以看到,多个线程同时进入这个方法,并不是等待一个线程执行完之后,另一个线程再开始执行。
下面探索synchronized类锁的作用:
一、static方法体中,使用synchronized(XX.class){...}
。不同线程访问同一个类的static方法时,不管是不是同一个方法,都会产生互斥。这种写法,常见于单例模式。
public class PrintFruit {
public static void printA(){
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" Apple");
}
public static void printB(){
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" Banana");
}
}
public class SyncTest {
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
synchronized (PrintFruit.class) {
PrintFruit.printA();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t1 = new Thread(r1, "t1");
Thread t2 = new Thread(r1,"t2");
Thread t3 = new Thread(r1, "t3");
Runnable r2 = new Runnable() {
@Override
public void run() {
synchronized (PrintFruit.class) {
PrintFruit.printB();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t4 = new Thread(r2, "t4");
Thread t5 = new Thread(r2, "t5");
Thread t6 = new Thread(r2, "t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
运行结果:
可以根据时间间隔看出,每隔3秒,下一个线程才开始执行代码块。即使printA和printB是两个不同的方法,也会出现互斥。
二、在static方法头中,加入synchronized
关键字。不同线程同时访问该类的static方法,即使是不同方法,也会产生互斥。
public class PrintTool {
public synchronized static void printC() {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" " + Thread.currentThread().getName() + "获得锁");
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "释放锁");
}
public synchronized static void printD() {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" " + Thread.currentThread().getName() + "获得锁");
System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + "释放锁");
}
}
public class SyncTest {
public static void main(String[] args) {
for (int i = 1; i <=3; i++) {
new Thread(new Runnable(){
@Override
public void run() {
PrintTool.printC();
}
}, "t" + i).start();
}
for (int i = 4; i <=6; i++) {
new Thread(new Runnable(){
@Override
public void run() {
PrintTool.printD();
}
}, "t" + i).start();
}
}
}
运行结果:
t1,t2,t3执行的是printC,t4,t5,t6执行的是printD。可以看到,即使是不同方法,也会出现互斥。
感谢:
synchronized(this) 与synchronized(class) 之间的区别
synchronized的四种用法
Java之Synchronized修饰实例方法和静态方法
Synchronized同步静态方法和非静态方法总结
以上是关于synchronized修饰方法static方法this.classobj的代码示例的主要内容,如果未能解决你的问题,请参考以下文章
synchronized修饰方法static方法this.classobj的代码示例