鎖的機制
以下代碼以使用手機發郵件和發短信爲例
線程的調度不是從上到下,而是和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