1、标准访问,请问先打印打电话还是发短信?
package demo1;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是发短信?
*/
public class Test01 {
public static void main(String[] args) {
Phone p = new Phone();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p.sendEmail();
},"B").start();
}
}
class Phone{
public synchronized void sendPhone(){
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
}
- 结论:先打电话再发短信。synchronized是方法锁,锁的对象是调用者,谁调用这个方法,谁就拿到了锁,上面的两个方法的调用这同一个,所以谁先调用谁先执行
2、标准访问,打电话方法暂停10秒,请问先打印打电话还是发短信?
package demo1;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
*/
public class Test01 {
public static void main(String[] args) {
Phone p = new Phone();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p.sendEmail();
},"B").start();
}
}
class Phone{
public synchronized void sendPhone(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
}
- 结论:被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以
两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能
执行。
3、新增一个普通方法hello()没有同步,请问先打电话还是hello?
package demo2;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3、新增一个普通方法hello()没有同步,请问先打印邮件还是hello?
*/
public class Test02 {
public static void main(String[] args) {
Phone2 p = new Phone2();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p.sendHello();
},"B").start();
}
}
class Phone2{
public synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
public void sendHello(){
System.out.println("Hello");
}
}
- 结论:先打印hello,后打印打电话。新增的方法没有被synchronized修饰,不是同步方法,不受所的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。
4、两部手机、请问先打电话还是短信?
package demo2;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3.新增一个普通方法hello()没有同步,请问先打电话还是hello?
* 4、两部手机、请问先打电话还是短信?
*/
public class Test02 {
public static void main(String[] args) {
Phone2 p = new Phone2();
Phone2 p2 = new Phone2();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p2.sendEmail();
},"B").start();
}
}
class Phone2{
public synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
}
- 结论:先发短信,后打电话。被synchronized锁住的方法,锁的对象是方法的调用者。这里因为用了两个对象,各自调用了各自的方法,两个不一样的锁,互不干涉。所以后一个方法不用等先调用的方法结束。
5、两个静态同步方法,同一部手机,请问先打电话还是先发短信?
package demo3;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3.新增一个普通方法hello()没有同步,请问先打电话还是hello?
* 4、两部手机、请问先打电话还是短信?
* 5.两个静态同步方法,同一部手机,请问先打电话还是先发短信?
*/
public class Test03 {
public static void main(String[] args) {
Phone3 p = new Phone3();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p.sendEmail();
},"B").start();
}
}
class Phone3{
public static synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public static synchronized void sendEmail(){
System.out.println("发短信");
}
}
结论:先打电话,后发短信。被synchronized和static修饰的方法,锁住的对象是类的class对象。因为两个方法都被static修饰,所以两个方法用的是同一把锁,后调用的方法需要等待先调用的方法。
6.两个静态同步方法,2部手机,请问先打电话还是短信?
package demo3;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3.新增一个普通方法hello()没有同步,请问先打电话还是hello?
* 4、两部手机、请问先打电话还是短信?
* 5.两个静态同步方法,同一部手机,请问先打电话还是先发短信?
* 6.两个静态同步方法,2部手机,请问先打电话还是短信?
*/
public class Test03 {
public static void main(String[] args) {
Phone3 p = new Phone3();
Phone3 p2 = new Phone3();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p2.sendEmail();
},"B").start();
}
}
class Phone3{
public static synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public static synchronized void sendEmail(){
System.out.println("发短信");
}
}
- 结论:先打电话,后发短信。被synchronized和static修饰的方法,锁住的对象是类的class对象。因为两个方法都被static修饰,即便用了两个不同的对象调用方法,两个方法还是同一把锁,后调用的需要等待先调用的。
7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印电话还是短信?
package Test04;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3.新增一个普通方法hello()没有同步,请问先打电话还是hello?
* 4、两部手机、请问先打电话还是短信?
* 5.两个静态同步方法,同一部手机,请问先打电话还是先发短信?
* 6.两个静态同步方法,2部手机,请问先打电话还是短信?
* 7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印电话还是短信?
*/
public class Test04 {
public static void main(String[] args) {
Phone3 p = new Phone3();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p.sendEmail();
},"B").start();
}
}
class Phone3{
public static synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
}
-
- 结论:先发短信,后打电话。被synchronized和static修饰的方法,锁住的对象是类的class对象。只被synchronized修饰的方法是同步方法,锁的对象是方法的调用者,因为两个方法锁的对象不是同一个,所以两个方法不是同一把锁
8、一个普通同步方法,一个静态同步方法,2部手机,请问先打电话还是先发短信?
package Test04;
import java.util.concurrent.TimeUnit;
/**
* 多线程的8锁
* 1、标准访问,请问先打电话还是先发短信?
* 2.让打电话方法暂停10秒,请问先打电话还是先发短信?
* 3.新增一个普通方法hello()没有同步,请问先打电话还是hello?
* 4、两部手机、请问先打电话还是短信?
* 5.两个静态同步方法,同一部手机,请问先打电话还是先发短信?
* 6.两个静态同步方法,2部手机,请问先打电话还是短信?
* 7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印电话还是短信?
* 8、一个普通同步方法,一个静态同步方法,2部手机,请问先打电话还是先发短信?
*/
public class Test04 {
public static void main(String[] args) {
Phone3 p = new Phone3();
Phone3 p2 = new Phone3();
new Thread(()->{
p.sendPhone();
},"A").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
p2.sendEmail();
},"B").start();
}
}
class Phone3{
public static synchronized void sendPhone(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话");
}
public synchronized void sendEmail(){
System.out.println("发短信");
}
}
- 结论:被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
小结:
-
new this 具体的一个手机
-
static class 唯一的一个模板
-
一个对象里面如果有多个synchronized方法,某个时刻内,只要一个线程去调用其中一个synchronized方法了,其他的线程都要等待,换句话说,在某个时刻内,只能有唯一一个线程去访问这些synchronized方法,锁的是当前对象this,被锁定后,其他的线程都不能进入到当前对象的其他的synchronized方法
加个普通方法后发现和同步锁无关,换成两个对象后,不是同一把锁,情况立刻变化
都换成静态同步方法后,情况又变化了。
所有的非静态的同步方法用的都是同一把锁----实例对象本身
synchronized实现同步的基础:java中的每一个对象都可以作为锁 -
具体的表现为以下三种形式:
对于普通同步方法,锁的是当前实例对象
对于静态同步方法,锁的是当前的Class对象。
对于同步方法块,锁是synchronized括号里面的配置对象 -
当一个线程试图访问同步代码块时,他首先必须得到锁,退出或者是抛出异常时必须释放锁,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可以是别的实例对象非非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以必须等待该实例对象已经获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
-
所有的静态同步方法用的也是同一把锁----类对象本身
这两把锁的是两个不同的对象,所以静态的同步方法与非静态的同步方法之间是不会有竞争条件的,但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要他们用一个的是同一个类的实例对象。