锁的机制
以下代码以使用手机发邮件和发短信为例
线程的调度不是从上到下,而是和CPU相关。
两个线程在访问资源类的时候不是同时进入,锁是锁的当前对象,一旦A中锁住了方法sendEmail,则B只能等待A执行完方法后才能执行sendMessage
1、标准访问
// 资源类
class Phone{
public synchronized void sendMessage() throw Exception{
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
phone.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:一个对象里面如果有多个synchronized 方法,某一时刻内,只要一个线程去调用了一个synchronized方法,其它线程只能等待。
也就是说某一时刻内,只能有唯一一个线程去访问这些synchronized方法。
*****sendEmail
*********sendMessage
2、在邮件方法中暂停4S
// 资源类
class Phone{
public synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
phone.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:
*****sendEmail
*********sendMessage
3、新增普通方法sayHello
// 资源类
class Phone{
public synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
public void sayHello() throw Exception{
System.out.println("*******sayHello");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//普通方法
phone.sayHello();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:
*******sayHello
*****sendEmail
4、两部手机
// 资源类
class Phone{
public synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
Phone phone2=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//第二部手机发短信
phone2.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:换了对象,不是同一个资源类,所以情况发生了变化,不同的锁
*********sendMessage
*****sendEmail
5、两个静态同步方法,同一部手机
// 资源类
class Phone{
public static synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public static synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//同一部手机调用静态同步方法
phone.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:由于static是修饰类的,加锁后,是将整个class锁住,static修饰的锁属于全局锁,而非对象锁
*****sendEmail
*********sendMessage
6、两个静态同步方法,两部手机
// 资源类
class Phone{
public static synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public static synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
Phone phone2=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//第二部手机调用发短信的方法
phone2.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:由于static是修饰类的,加锁后,是将整个class锁住,static修饰的锁属于全局锁,而非对象锁。对于静态同步方法,锁的是当前class
*****sendEmail
*********sendMessage
7、一个静态同步方法,一个普通同步方法
// 资源类
class Phone{
public static synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//调用普通同步方法
phone.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:锁的对象是不一样的,一个 锁的是当前对象,另一个锁的是整个class。
*********sendMessage
*****sendEmail
8、一个静态同步方法,一个普通方法,两部手机
// 资源类
class Phone{
public static synchronized void sendMessage() throw Exception{
//暂停4秒,此方法来自Java.util.concurent包
TimeUnit.Seconds.sleep(4);
System.out.println("*********sendMessage");
}
public synchronized void sendEmail() throw Exception{
System.out.println("*****sendEmail");
}
}
// 用于执行线程
public class LockDemo{
public static void main(String[] args){
Phone phone=new Phone();
Phone phone2=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch(Exception e){
e.printStackTrace();
}
},"A").start;
//睡眠1ms,人为让A线程先于B线程执行
Thread.sleep(100);
new Thread(()->{
try{
//调用普通同步方法
phone2.sendMessage();
}catch(Exception e){
e.printStackTrace();
}
},"B").start;
}
}
执行结果:全局锁和对象锁是两个不同的东西,实际上并无关系。一个是小米工厂,一个是小米手机
*********sendMessage
*****sendEmail