執行緒第六課(附加)——八鎖問題
搞懂以下八個問題,同步鎖就算真的搞懂了。
1 標準訪問,先列印簡訊還是郵件
public class Lock_8 { public static void main(String[] args) throws InterruptedException { Phone phone1 = new Phone(); Phone phone2 = new Phone(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { phone1.sendSMS(); } },"AA"); Thread.sleep(100); Thread thread2 = new Thread(new Runnable() { @Override public void run() { phone1.sendEmail(); } },"BB"); } } class Phone { public synchronized void sendSMS() { System.out.println("------sendSMS"); } public synchronized void sendEmail() { System.out.println("------sendEmail"); } }
2 停4秒在簡訊方法內,先列印簡訊還是郵件
public class Lock_8 { public static void main(String[] args) throws InterruptedException { Phone phone1 = new Phone(); Phone phone2 = new Phone(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { phone1.sendSMS(); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA"); Thread.sleep(100); Thread thread2 = new Thread(new Runnable() { @Override public void run() { phone1.sendEmail(); } },"BB"); } } class Phone { public synchronized void sendSMS() throws InterruptedException { Thread.sleep(4 * 1000); System.out.println("------sendSMS"); } public synchronized void sendEmail() { System.out.println("------sendEmail"); } }
3 普通的hello方法,是先打簡訊還是hello
public class Lock_8 { public static void main(String[] args) throws InterruptedException { Phone phone1 = new Phone(); Phone phone2 = new Phone(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { phone1.sendSMS(); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA"); Thread.sleep(100); Thread thread2 = new Thread(new Runnable() { @Override public void run() { phone1.getHello(); } },"BB"); } } class Phone { public synchronized void sendSMS() throws InterruptedException { Thread.sleep(4 * 1000); System.out.println("------sendSMS"); } public synchronized void sendEmail() { System.out.println("------sendEmail"); } public void getHello() { System.out.println("------getHello"); } }
4 現在有兩部手機,先列印簡訊還是郵件
public class Lock_8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
phone1.sendSMS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA");
Thread.sleep(100);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
phone2.sendEmail();
}
},"BB");
}
}
class Phone
{
public synchronized void sendSMS() throws InterruptedException {
Thread.sleep(4 * 1000);
System.out.println("------sendSMS");
}
public synchronized void sendEmail()
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
5 兩個靜態同步方法,1部手機,先列印簡訊還是郵件
public class Lock_8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
phone1.sendSMS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA");
Thread.sleep(100);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
phone1.sendEmail();
}
},"BB");
}
}
class Phone
{
public synchronized static void sendSMS() throws InterruptedException {
Thread.sleep(4 * 1000);
System.out.println("------sendSMS");
}
public synchronized static void sendEmail()
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
6 兩個靜態同步方法,2部手機,先列印簡訊還是郵件
public class Lock_8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
phone1.sendSMS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA");
Thread.sleep(100);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
phone2.sendEmail();
}
},"BB");
}
}
class Phone
{
public synchronized static void sendSMS() throws InterruptedException {
Thread.sleep(4 * 1000);
System.out.println("------sendSMS");
}
public synchronized static void sendEmail()
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
7 1個靜態同步方法,1個普通同步方法,1部手機,先列印簡訊還是郵件
public class Lock_8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
phone1.sendSMS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA");
Thread.sleep(100);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
phone1.sendEmail();
}
},"BB");
}
}
class Phone
{
public synchronized static void sendSMS() throws InterruptedException {
Thread.sleep(4 * 1000);
System.out.println("------sendSMS");
}
public static void sendEmail()
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
8 1個靜態同步方法,1個普通同步方法,2部手機,先列印簡訊還是郵件
public class Lock_8 {
public static void main(String[] args) throws InterruptedException {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
phone1.sendSMS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA");
Thread.sleep(100);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
phone2.sendEmail();
}
},"BB");
}
}
class Phone
{
public synchronized static void sendSMS() throws InterruptedException {
Thread.sleep(4 * 1000);
System.out.println("------sendSMS");
}
public static void sendEmail()
{
System.out.println("------sendEmail");
}
public void getHello()
{
System.out.println("------getHello");
}
}
分析:
A 一個物件裡面如果有多個synchronized方法,某一個時刻內,只要一個執行緒去呼叫其中的一個synchronized方法了,
其它的執行緒都只能等待,換句話說,某一個時刻內,只能有唯一一個執行緒去訪問這些synchronized方法
鎖的是當前物件this,被鎖定後,其它的執行緒都不能進入到當前物件的其它的synchronized方法
加個普通方法後發現和同步鎖無關
換成兩個物件後,不是同一把鎖了,情況立刻變化。
synchronized實現同步的基礎:Java中的每一個物件都可以作為鎖。
具體表現為以下3種形式。
對於普通同步方法,鎖是當前例項物件。
對於靜態同步方法,鎖是當前類的Class物件。
對於同步方法塊,鎖是Synchonized括號裡配置的物件
當一個執行緒試圖訪問同步程式碼塊時,它首先必須得到鎖,退出或丟擲異常時必須釋放鎖。
也就是說如果一個例項物件的非靜態同步方法獲取鎖後,該例項物件的其他非靜態同步方法必須等待獲取鎖的方法釋放鎖後才能獲取鎖,
可是別的例項物件的非靜態同步方法因為跟該例項物件的非靜態同步方法用的是不同的鎖,
所以毋須等待該例項物件已獲取鎖的非靜態同步方法釋放鎖就可以獲取他們自己的鎖。
所有的靜態同步方法用的也是同一把鎖——類物件本身,
這兩把鎖是兩個不同的物件,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。
但是一旦一個靜態同步方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖,
而不管是同一個例項物件的靜態同步方法之間,
還是不同的例項物件的靜態同步方法之間,只要它們同一個類的例項物件!