1、synchronized修饰类的普通方法
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
public void run(){
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"正在打印i="+i);
}
}
//被synchronized修饰的普通方法
public synchronized void print() {
System.out.println(Thread.currentThread().getName()+"线程开始执行......");
run();
System.out.println(Thread.currentThread().getName()+"线程执行结束......");
}
}
测试类如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
SynchronizedClass p=new SynchronizedClass();
//创建t1线程
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
p.print();
}
});
t1.setName("t1");
//创建t2线程
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
p.print();
}
});
t2.setName("t2");
//启动线程
t1.start();
t2.start();
}
}
测试类运行结果:
t1线程开始执行......
线程t1正在打印i=0
线程t1正在打印i=1
线程t1正在打印i=2
线程t1正在打印i=3
线程t1正在打印i=4
t1线程执行结束......
t2线程开始执行......
线程t2正在打印i=0
线程t2正在打印i=1
线程t2正在打印i=2
线程t2正在打印i=3
线程t2正在打印i=4
t2线程执行结束......
从运行结果来看,线程t1和线程t2是同步执行print方法的,这是因为两个线程中都是通过同一个对象p来调用print方法的,当t1开始执行p.print()时,会取得对象p的锁,此时线程t2拿不到对象p的锁无法操作p的print方法,等线程t1执行完毕释放对象p的锁,此时线程t2才可以拿到p的锁来执行print方法。如果创建两个对象p1和p2,线程t1和t2分别使用两个对象来调用print方法,此时测试类修改如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
SynchronizedClass p1=new SynchronizedClass();
SynchronizedClass p2=new SynchronizedClass();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
p1.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
p2.print();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
程序运行结果如下:
t1线程开始执行......
t2线程开始执行......
线程t2正在打印i=0
线程t1正在打印i=0
线程t2正在打印i=1
线程t1正在打印i=1
线程t1正在打印i=2
线程t2正在打印i=2
线程t1正在打印i=3
线程t2正在打印i=3
线程t1正在打印i=4
t1线程执行结束......
线程t2正在打印i=4
t2线程执行结束......
此时,线程t1和t2是异步执行的,因为此时线程t1拿到的是p1对象的锁,和对象p2无关,线程t2执行p2.print时会取得p2的锁,互不影响。
2、synchronized修饰普通方法中的代码块
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
public void run(){
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"正在打印i="+i);
}
}
public void print() {
synchronized (this){
System.out.println(Thread.currentThread().getName()+"线程开始执行......");
run();
System.out.println(Thread.currentThread().getName()+"线程执行结束......");
}
}
}
这种方式和1相同。
3、synchronized修饰类的静态方法
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
public static void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
public synchronized static void print() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
}
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
SynchronizedClass.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
SynchronizedClass.print();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
程序运行结果:
t1线程开始执行......
线程t1正在打印i=0
线程t1正在打印i=1
线程t1正在打印i=2
线程t1正在打印i=3
线程t1正在打印i=4
t1线程执行结束......
t2线程开始执行......
线程t2正在打印i=0
线程t2正在打印i=1
线程t2正在打印i=2
线程t2正在打印i=3
线程t2正在打印i=4
t2线程执行结束......
从结果来看,我们发现线程t1和线程t2是同步执行的。SynchronizedClass.print()改成对象 new SynchronizedClass().print()调用也是同步执行的。这是因为线程t1执行SynchronizedClass.print()时,取得类的锁(因为静态方法是属于类的),在未执行完前,线程t2无法取得该类的锁,当线程t1执行完后,释放类的锁,此时线程t2可以拿到类的锁去执行SynchronizedClass.print()。
4、synchronized修饰静态方法中的代码块
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
public static void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
public static void print() {
synchronized(SynchronizedClass.class){
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
}
}
这种方式与第3种方式相同。
5、如果synchronized修饰了某个静态方法,该类是否还可以调用其他无synchronized关键字修饰的静态方法?
答案是可以的。如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
//无synchronized修饰的静态方法
public static void otherPrint() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
//synchronized修饰的静态方法
public synchronized static void print() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
public static void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
}
测试类如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
//调用synchronized修饰的静态方法
SynchronizedClass.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
//调用无synchronized修饰的静态方法
SynchronizedClass.otherPrint();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
程序运行结果:
t1线程开始执行......
t2线程开始执行......
线程t1正在打印i=0
线程t2正在打印i=0
线程t2正在打印i=1
线程t1正在打印i=1
线程t2正在打印i=2
线程t1正在打印i=2
线程t2正在打印i=3
线程t1正在打印i=3
线程t2正在打印i=4
线程t1正在打印i=4
t1线程执行结束......
t2线程执行结束......
从程序运行结果来看,互不影响。这是因为线程t1执行SynchronizedClass.print();时取得类锁,但是线程t2执行SynchronizedClass.otherPrint();不需要锁,可以直接执行。
6、如果synchronized修饰了某个普通方法,当某个线程通过对象调用该普通方法时,该对象是否还可以调用其他无synchronized关键字修饰的普通方法?
答案是可以的。自行测试。
7、如果类中有两个synchronized修饰的普通方法,那么两个线程是否可以通过同一个对象并发调用这两个方法?
答案是不可以的。原因是执行synchronized修饰的方法必须取得对象锁。如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
//synchronized修饰的普通方法
public synchronized void otherPrint() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
//synchronized修饰的普通方法
public synchronized void print() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
}
测试类如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
SynchronizedClass p=new SynchronizedClass();
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
//调用synchronized修饰的静态方法
p.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
//调用无synchronized修饰的静态方法
p.otherPrint();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
测试类运行结果如下:
t1线程开始执行......
线程t1正在打印i=0
线程t1正在打印i=1
线程t1正在打印i=2
线程t1正在打印i=3
线程t1正在打印i=4
t1线程执行结束......
t2线程开始执行......
线程t2正在打印i=0
线程t2正在打印i=1
线程t2正在打印i=2
线程t2正在打印i=3
线程t2正在打印i=4
t2线程执行结束......
8、如果类中有两个synchronized修饰的静态方法,那么两个线程是否可以并发调用这两个方法?
答案是不可以的。这是因为执行synchronized修饰的静态方法必须取得类锁。如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
//synchronized修饰的静态方法
public synchronized static void otherPrint() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
//synchronized修饰的静态方法
public synchronized static void print() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
public static void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
}
测试类如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
//调用synchronized修饰的静态方法
SynchronizedClass.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
//调用无synchronized修饰的静态方法
SynchronizedClass.otherPrint();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
测试类运行结果:
t2线程开始执行......
线程t2正在打印i=0
线程t2正在打印i=1
线程t2正在打印i=2
线程t2正在打印i=3
线程t2正在打印i=4
t2线程执行结束......
t1线程开始执行......
线程t1正在打印i=0
线程t1正在打印i=1
线程t1正在打印i=2
线程t1正在打印i=3
线程t1正在打印i=4
t1线程执行结束......
9、如果类中一个是synchronized修饰的静态方法,另一个是synchronized修饰的普通方法,那么两个线程是否可以并发调用这两个方法?
答案是可以的。这是因为一个是对象锁,一个是类锁,不是同一把锁。如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
* 测试synchronized关键字使用
*/
public class SynchronizedClass {
//synchronized修饰的普通方法
public synchronized void otherPrint() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
//synchronized修饰的静态方法
public synchronized static void print() {
System.out.println(Thread.currentThread().getName() + "线程开始执行......");
run();
System.out.println(Thread.currentThread().getName() + "线程执行结束......");
}
public static void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "正在打印i=" + i);
}
}
}
测试类如下:
package main.thread;
/**
* Created by leboop on 2018/11/18.
*/
public class SychronizedTest {
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
//调用synchronized修饰的静态方法
SynchronizedClass.print();
}
});
t1.setName("t1");
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
//调用无synchronized修饰的静态方法
new SynchronizedClass().otherPrint();
}
});
t2.setName("t2");
t1.start();
t2.start();
}
}
运行结果如下:
t1线程开始执行......
t2线程开始执行......
线程t1正在打印i=0
线程t2正在打印i=0
线程t1正在打印i=1
线程t2正在打印i=1
线程t2正在打印i=2
线程t1正在打印i=2
线程t1正在打印i=3
线程t2正在打印i=3
线程t1正在打印i=4
线程t2正在打印i=4
t2线程执行结束......
t1线程执行结束......
注意:类锁和对象锁不是一把锁。每个对象都有一把锁与之相关。