1.两个线程调用同一个对象的两个同步方法
public class ThreadDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
*/
public synchronized void sendSms(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行的结果如下
发短信
打电话
结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行。
2.新增Thread.sleep()给某个方法
public class ThreadDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
*/
public synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
// 等待4秒。
发短信
打电话
结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。
3.新增一个线程调用新增的一个普通方法
public class ThreadDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
new Thread(()->{
phone.hello();
},"C").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
*/
public synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
/**
* 这里没有锁!不是同步方法,不受锁的影响
*/
public void hello(){
System.out.println("hello");
}
}
运行结果:
hello
//等待4秒
发短信
打电话
结果分析:新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。
4.两个线程调用两个对象的同步方法,并且睡眠其中一个
public class ThreadDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 =new Phone();
new Thread(()->{
phone1.sendSms();
},"A").start();
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
*/
public synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
/**
* 这里没有锁!不是同步方法,不受锁的影响
*/
public void hello(){
System.out.println("hello");
}
}
运行结果
打电话
//等待4秒
发短信
结果分析:被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
5.增加两个静态的同步代码,同一个对象去调用不同的代码块
public class ThreadDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 =new Phone();
new Thread(()->{
phone1.sendSms();
},"A").start();
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
* static 类一加载就有了!锁的是Class
*/
public static synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
//等待4秒
发短信
打电话
结论:被synchronized和static修饰的方法,锁的对象是类的class对象,因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法
6.两个对象调用两个静态的同步方法
public class ThreadDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 =new Phone();
new Thread(()->{
phone1.sendSms();
},"A").start();
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
* static 类一加载就有了!锁的是Class
*/
public static synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
//等待4秒
发短信
打电话
结论:被synchronized和static修饰的方法,锁的对象是类的class对象,因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法
7.1个静态的同步方法,1个普通的同步方法 ,使用一个对象调用
public class ThreadDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 =new Phone();
new Thread(()->{
phone1.sendSms();
},"A").start();
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
* static 类一加载就有了!锁的是Class
*/
public static synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
/**
* 普通的同步方法 锁的调用者
*/
public synchronized void call(){
System.out.println("打电话");
}
}
打电话
//等待4秒
发短信
结论:被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
8.1个静态的同步方法,1个普通的同步方法 ,使用两个对象调用
public class ThreadDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 =new Phone();
new Thread(()->{
phone1.sendSms();
},"A").start();
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone{
/**
* synchronized 锁的对象是方法的调用者!、
* 两个方法用的是同一个锁,谁先拿到谁执行!
* static 类一加载就有了!锁的是Class
*/
public static synchronized void sendSms(){
try {
//睡眠4秒钟
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
/**
* 普通的同步方法 锁的调用者
*/
public synchronized void call(){
System.out.println("打电话");
}
}
打电话
//等待4秒
发短信
结论:被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
总结:
1.一个类有多个synchronized 方法,被同一个对象调用时候,后来者必须进行等待,等待先来者释放才可以进行访问。
2.普通方法与同步方法无关
3.加入static修饰的方法,锁的是类
4.不同对象或者同一对象调用同一类中的不同静态同步代码块,后来者必须进行等待,等待先来者释放才可以进行访问。