Java学习笔记十五
26.
下面介紹synchronized代碼塊,個人以為,重要度遠遠高于單純的修飾synchronized方法:
一方面:高效率!
另一方面:后面涉及到的wait和notify方法,都要涉及
Synchronized要修飾一個對象
即:synchronized(Object);
表示將對象object上鎖,這里的object對象其實是沒有用的,只是說明被上鎖,個人建議使用this關鍵字,表示將當前對象上鎖!
看下面的synchronized代碼塊代碼同樣實現了兩個方法的順序執行:
?
?
?
package thread;
?
public class BlockTest
{
?? public static void main(String[] args)
?? {
????? Block block = new Block();
????? ThreadTestX test1 = new ThreadTestX(block);
????? ThreadTestXX test2 = new ThreadTestXX(block);
????? test1.start();
????? test2.start();
?? }
}
class Block
{
?? public void method1()
?? {
????? synchronized (this)
????? {
??????? for(int i = 0; i < 15; i++)
??????? {
?????????? System.out.println("hello :"+ i);
??????????
??????? ??
??????? }
????? }
?? }
?? public void method2()
?? {
????? synchronized(this)
????? {
??????? for(int i = 0 ; i <15; i ++)
??????? {
?????????? System.out.println("world!"+ i);
??????????
??????? }
????? }
?? }
}
class ThreadTestXextends Thread
{
?? private Blockblock;
?? public ThreadTestX(Block block)
?? {
????? this.block = block;
?? }
?? @Override
?? public void run()
?? {
????? block.method1();
?? }
??
}
class ThreadTestXXextends Thread
{
?? private Blockblock;
?? public ThreadTestXX(Block block)
?? {
????? this.block = block;
?? }
?? @Override
?? public void run()
?? {
????? block.method2();
?? }
??
}
?
?
?
27.
Deadlock:
所謂死鎖<DeadLock>:是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去.此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程.
產生deadlock的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個進程使用。
(2) 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
(4) 循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之
一不滿足,就不會發生死鎖。
?
28.
一個線程就是一個類!
?
?
29.
Object類中的wait 、和 notify方法是用來處理線程的方法,既然定義在Object類中,兩個方法的重要程度可見一斑:
兩個方法的使用上都很復雜:通過閱讀API獲得更多對方法的理解:
The current thread must own this object'smonitor. The thread releases ownership of this monitor and waits until anotherthread notifies threads waiting on this object's monitor to wake up eitherthrough a call to thenotify method or the notifyAll method. The thread then waits until it can re-obtain ownership ofthe monitor and resumes execution
?
?
“當前的線程必須要獲得對象的鎖!”
實現這個條件的做法就是wait 方法一定要定義在synchronized方法中或者synchronized代碼塊中;
線程必須要兩次獲得鎖才能完全的執行synchronized中的所有內容;
當第一次調用到達wait方法時,The thread realeases ownership of this monitor and waituntil another thread notifies threads waiting on this …
線程會暫時釋放鎖的擁有權,等待其他線程的notify方法或者notifyAll方法喚醒該線程,繼續執行代碼!
?
?
?
30.
下面一個程序要求定義兩個線程類,一個實現將目標加一,一個實現將目標減一,目標初始值為零,要求加一減一交替進行;
顯然的單純調用synchronized是無法滿足條件的,需要使用wait,和notify方法;
?
package thread;
?
public class ThreadTest
{
?
?? public static void main(String[] args)
?? {
????? ThreadDemo2 demo = new ThreadDemo2();
????? ThreadIncrease test1 = new ThreadIncrease(demo);
????? ThreadDecrease test2 = new ThreadDecrease(demo);
????? test1.start();
????? test2.start();
?? }
}
class ThreadDemo2
{
?? private int num = 0;
?? public synchronized void Increase()
?? {
????? /*
????? ?* 下面的代碼是核心代碼
????? ?* 什么時候要讓線程等待,當然是不符合條件的時候
????? ?* 目的是想讓num = 0的時候才執行加一的操作,當num不等于零的時候會執行wait等待通知
????? ?* 當通知num已經變為0時,wait結束,執行下面語句num++;
????? ?* 然后執行notify方法!
????? ?* 當然的一說Java中的synchronized總是伴隨著wait和notify方法共同的存在;
????? ?*/
?????
????? if(num != 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num ++;
????? System.out.println(num);
????? notify();
????? }
??
?? public synchronized void decrease()
?? {
?????
????? if(num == 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num --;
????? System.out.println(num);
?????
????? notify();
????? }
?????
??
}
class ThreadIncreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadIncrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?? }
?? @Override
?? public void run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
????? demo.Increase();
????? }
?? }
??
}
class ThreadDecreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadDecrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?????
?? }
?? @Override
?? public void run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
????? demo.decrease();
????? }
?? }
}
?
?
?
31.
可惜的是上面的代碼仍然有著致命的弱點,線程并不僅僅有兩個,而且是兩個相對的線程!
致命的弱點在于: 當線程在wait的時候它并不知道其他的線程到底做了什么!
現在我們將增加一個Increase線程類,和一個Decrease線程類
,并且調用它們的start方法運行后,你將看到這樣的結果:
我們足以看到代碼的脆弱性,為什么會出現這種情況,更糟糕的是結果是隨機的!上面已經說得很清楚了:當線程在wait的時候,它不知道其他的線程正在做什么,
所以需要將代碼變得更加健壯:
我們舉一個為什么會出現這種情況的原因之一:
我們假設線程1、2調用增加方法,線程3、4調用減少方法
假設線程3 先訪問了減少方法,因為此時num的值為0,所以wait,并且交出ownership,假設線程4又訪問了減少方法,同樣的wait,并且交出所有權,再假設線程1訪問了增加方法,將num的值變為1,并且調用notify方法,假設notify了線程3,線程3將num的值變為0;并且notify,如果此時notify了線程4,那么悲劇就會發生了,線程4醒來后,會繼續將num減一,變為-1,一步錯,后面就全錯了;
缺點就在于notify的隨機性,所以在某個wait方法被喚醒時,增加判斷條件,如果不符合條件,繼續wait,顯然 while循環是最合適的
!
全部的變化只需要將 if 改為 while!!
由于num是成員變量被線程共享,每當wait被喚醒,都會判斷一次;
package thread;
?
public class ThreadTest
{
?
?? public static void main(String[] args)
?? {
????? ThreadDemo2 demo = new ThreadDemo2();
????? ThreadIncrease test1 = new ThreadIncrease(demo);
????? ThreadDecrease test2 = new ThreadDecrease(demo);
????? ThreadIncrease test3 = new ThreadIncrease(demo);
????? ThreadDecrease test4 = new ThreadDecrease(demo);
????? test1.start();
????? test2.start();
????? test3.start();
????? test4.start();
?? }
}
class ThreadDemo2
{
?? private int num = 0;
?? public synchronized void Increase()
?? {
????? /*
????? ?* 下面的代碼是核心代碼
????? ?* 什么時候要讓線程等待,當然是不符合條件的時候
????? ?* 目的是想讓num = 0的時候才執行加一的操作,當num不等于零的時候會執行wait等待通知
????? ?* 當通知num已經變為0時,wait結束,執行下面語句num++;
????? ?* 然后執行notify方法!
????? ?* 當然的一說Java中的synchronized總是伴隨著wait和notify方法共同的存在;
????? ?*/
?????
?? ?? while(num != 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num ++;
????? System.out.println(num);
????? notify();
????? }
??
?? public synchronized void decrease()
?? {
?????
????? while(num == 0)
????? {
??????? try
??????? {
?????????? wait();
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
????? }
????? num --;
????? System.out.println(num);
?????
????? notify();
????? }
?????
??
}
class ThreadIncreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadIncrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?? }
?? @Override
?? public void run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
??????? try
??????? {
?????????? Thread.sleep((long)(Math.random()*1000));
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
??????? demo.Increase();
????? }
?? }
??
}
class ThreadDecreaseextends Thread
{
?? private ThreadDemo2demo;
?? public ThreadDecrease(ThreadDemo2 demo)
?? {
????? this.demo = demo;
?????
?? }
?? @Override
?? public void run()
?? {
????? for(int i = 0 ; i < 15; i ++)
????? {
??????? try
??????? {
?????????? Thread.sleep((long)(Math.random()*1000));
??????? }
??????? catch (InterruptedException e)
??????? {
?????????? // TODO Auto-generatedcatch block
?????????? e.printStackTrace();
??????? }
??????? demo.decrease();
????? }
?? }
}
?
?
?
?
?
?
?
?
?
32.
Object 中最后一個方法—— colone;
首先介紹淺克隆,被克隆的類必須實現了Cloneable接口
該接口是一個標識接口!
克隆的只是對象!
對于任何的拷貝對象X;一定有
1. X.clone() != X;
?? 即克隆的對象與原對象肯定不是一個對象;
1.X.clone().getClass() ==x.getClass();
一個類不管有多少個對象,它們都有著共同的一個類!
2.如果設計的合適的話
x.clone().equals(x)是正確的;
?
下面是淺克隆:
package com.jianjian.clone;
?
public class CloneTest1
{
?? public static void main(String[] args)throws CloneNotSupportedException
?? {
????? Person person = new Person();
????? person.setAge(20);
????? person.setName("yangmanman");
????? Person person1 = (Person)person.clone();//注意到返回的對象是Object類型的,不要忘記類型轉換;
????? System.out.println(person1.getAge());
????? System.out.println(person1.getName());
????? System.out.println(person1 == person);
????? System.out.println(person1.getClass() == person.getClass());
????? System.out.println(person1.equals(person));//我重寫了equals方法;將結果返回true
?? }
}
class Person implements Cloneable
{
?? private int age;
?? private Stringname;
?? public int getAge()
?? {
????? return age;
?? }
?? public void setAge(int age)
?? {
????? this.age = age;
?? }
?? public String getName()
?? {
????? return name;
?? }
?? public void setName(String name)
?? {
????? this.name = name;
?? }
?? @Override//需要重寫clone方法;
?? protected Object clone()throws CloneNotSupportedException
?? {
?????
????? Object object = super.clone();
????? return object;
?????
?? }
?? @Override
?? public int hashCode()
?? {
????? final int prime = 31;
????? int result = 1;
????? result = prime * result + age;
????? result = prime * result + ((name ==null) ? 0 :name.hashCode());
????? return result;
?? }
?? @Override
?? public boolean equals(Object obj)
?? {
????? if (this == obj)
??????? return true;
????? if (obj ==null)
??????? return false;
????? if (getClass() != obj.getClass())
??????? return false;
????? Person other = (Person) obj;
????? if (age != other.age)
??????? return false;
????? if (name ==null)
????? {
??????? if (other.name !=null)
?????????? return false;
????? }
????? else if (!name.equals(other.name))
??????? return false;
????? return true;
?? }
??
??
}
?
33.
關于深克隆,以后深究
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的Java学习笔记十五的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java学习笔记十三
- 下一篇: Java高新技术笔记:反射、多线程、泛型