『壹』 java常見的幾種調用機制(同步調用,非同步調用
1、同步調用
同步調用是最基本的調用方式,對象b中的方法直接調用對象a的方法,這個時候程序會等待對象a的方法執行完返回結果之後才會繼續往下走。
代碼如下:
public class A {
public void methodA()
{
System.out.println("this is class A method");
}
}
public class B {
public void methodB()
{
A a = new A();
a.methodA();
System.out.println("this is class B method");
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.methodB();
}
}
結果:
this is class A method
this is class B method
2、非同步調用
對象b中的方法調用對象a的方法,程序並不需要等待對象a的方法返回結果值,直接繼續往下走。
代碼如下:
public class A extends Thread{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("this is class A method");
}
}
public class B {
public void methodB()
{
A a = new A();
a.start();
System.out.println("this is class B method");
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.methodB();
}
}
結果:
this is class B method
this is class A method
說明:非同步調用我們通常採用多線程的方法來達到目的
3、回調
對象a的方法methodA()中調用對象b的methodB()方法,在對象b的methodB()方法中反過來調用對象a的callBack()方法,這個callBack()方法稱為回調函數,這種調用方法稱為回調。
代碼如下:
public class A {
public void methodA()
{
B b = new B();
b.methodB(new A());
System.out.println("this is class A method : methodA");
}
public void callBack()
{
System.out.println("this is class A method : callBack");
}
}
public class B {
public void methodB(A a)
{
System.out.println("this is class B method : methodB");
a.callBack();
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.methodA();
}
}
運行結果:
this is class B method : methodB
this is class A method : callBack
this is class A method : methodA
注意:這里如果為了代碼的擴展性更好,可以把類A與類B抽象出一個介面出來,然後用實現類去實現著兩個介面,這樣代碼的擴展性會更好,也能滿足更多的業務場景。
回調的核心在於:回調方將本身對象傳給調用方,調用方在本身代碼邏輯執行完之後,調用回調方的回調方法。
『貳』 java同步鎖中synchronized和Lock介面類的區別
Java的synchronized加在方法上或者對象上區別如下:
1.synchronized
在方法上,所有這個類的加了
synchronized
的方法,內在執行時,會獲容得一個該類的唯一的同步鎖,當這個鎖被佔用時,其他的加了
synchronized
的方法就必須等待
『叄』 Java實現線程同步的幾種方式
java中多線程的實現方法有兩種:1.直接繼承thread類;2.實現runnable介面;同步的實現方法有五種:1.同步方法;2.同步代碼塊;3.使用特殊域變數(volatile)實現線程同步;4.使用重入鎖實現線程同步;5.使用局部變數實現線程同步 。
其中多線程實現過程中需注意重寫或者覆蓋run()方法,而對於同步的實現方法中使用較常使用的是利用synchronized編寫同步方法和代碼塊。
『肆』 Java 線程同步幾種方式
(1)同步來方法:
即有synchronized關鍵字修飾的自方法。 由於java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。
(2)同步代碼塊
即有synchronized關鍵字修飾的語句塊。被該關鍵字修飾的語句塊會自動被加上內置鎖,從而實現同步
(3)使用特殊域變數(Volatile)實現線程同步
a.volatile關鍵字為域變數的訪問提供了一種免鎖機制
b.使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新
c.因此每次使用該域就要重新計算,而不是使用寄存器中的值
d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變數
(4)使用重入鎖實現線程同步
在JavaSE5.0中新增了一個java.util.concurrent包來支持同步。ReentrantLock類是可重入、互斥、實現了Lock介面的鎖, 它與使用synchronized方法和快具有相同的基本行為和語義,並且擴展了其能力。
(5)使用局部變數實現線程同步
『伍』 java中實現同步的方法到底有哪兩種
synchronized 是正解,通常用在多線程裡面 wait相當於把當前位置讓出來給下一個線程,notify是喚醒一個睡眠的線程,希望採納
『陸』 同步介面和非同步介面的區別是什麼
Java中交互方式分為同步和非同步兩種:
同步交互:指發送一個請求,需要等待返回,然後才能夠發送下一個請求,有個等待過程;
非同步交互:指發送一個請求,不需要等待返回,隨時可以再發送下一個請求,即不需要等待。
區別:一個需要等待,一個不需要等待,在部分情況下,我們的項目開發中都會優先選擇不需要等待的非同步交互方式。
『柒』 java中線程同步的幾種方法
線程同步主要有以下種方法(示例中是實現計數的功能):
1、同步方法,即使用synchronized關鍵字修飾方法,例如:
publicsynchronizedvoidadd(intc){...}
2、同步代碼塊,即有synchronized關鍵字修飾的語句塊,例如:
publicvoidaddAndGet(intc){
synchronized(this){
count+=c;
}
}
3、使用特殊域變數(volatile)實現線程同步,該方法不能保證絕對的同步。
例如:privatevolatileintcount=0;
4、使用鎖實現線程同步,例如:
privateLocklock=newReentrantLock();
publicvoidadd(intc){
lock.lock();//上鎖
try{
count+=c;
}finally{
lock.unlock();//解鎖
}
}
5、使用原子變數實現線程同步,在java的util.concurrent.atomic包中提供了創建了原子類型變數的工具類,例如:
privateAtomicIntegercount=newAtomicInteger(1);
publicvoidadd(intc){
count.addAndGet(c);
}
6、使用局部變數實現線程同步,如果使用ThreadLocal管理變數,則每一個使用該變數的線程都獲得該變數的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變數副本,而不會對其他線程產生影響。
ThreadLocal 類的常用方法
new ThreadLocal<T>() : 創建一個線程本地變數
get() : 返回此線程局部變數的當前線程副本中的值
initialValue() : 返回此線程局部變數的當前線程的"初始值"
set(T value) : 將此線程局部變數的當前線程副本中的值設置為value
示例代碼:
privatestaticThreadLocal<Integer>count=newThreadLocal<Integer>(){
@Override
protectedIntegerinitialValue(){
return1;
}
};
publicvoidadd(intc){
count.set(count.get()+c);
}
7、使用阻塞隊列實現,例如LinkedBlockingQueue,具體使用可網路LinkedBlockingQueue的用法或查看java文檔。
『捌』 java同步和非同步的區別
java同步和非同步的區別如下:
一、根據情況需要專門的線程方式
如果數據將在線程間共享.例如正在寫的數據以後可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那麼這些數據就是共享數據,必須進行同步存取.
當應用程序在對象上調用了一個需要花費很長時間來執行的方法,並且不希望讓程序等待方法的返回時,就應該使用非同步編程,在很多情況下採用非同步途徑往往更有效率.
二、應用不同:
Java同步:
基本概念:每個Object都會有1個鎖.同步就是串列使用一些資源.
(說明:以下有些例子為了突出重點,省略了不必要的代碼.非凡是省掉了一些成員變數,就是需要同步的對象.)
1. 多線程中對共享、可變的數據進行同步.
對於函數中的局部變數沒必要進行同步.
對於不可變數據,也沒必要進行同步.
多線程中訪問共享可變數據才有必要.
2. 單個線程中可以使用synchronized,而且可以嵌套,但無意義.
class Test {
public static void main(String[] args) {
Test t = new Test();
synchronized(t) {
synchronized(t) {
System.out.println("ok!");
}
}
}
}
3. 對象實例的鎖
class Test{
public synchronized void f1(){
//do something here
}
public void f2(){
synchronized(this){
//do something here
}
}
}
上面的f1()和f2()效果一致, synchronized取得的鎖都是Test某個實列(this)的鎖.
比如: Test t = new Test();
線程A調用t.f2()時, 線程B無法進入t.f1(),直到t.f2()結束.
作用: 多線程中訪問Test的同一個實例的同步方法時會進行同步.
4. class的鎖
class Test{
final static Object o= new Object();
public static synchronized void f1(){
//do something here
}
public static void f2(){
synchronized(Test.class){
//do something here
}
}
public static void f3(){
try {
synchronized (Class.forName("Test")) {
//do something here
}
}
catch (ClassNotFoundException ex) {
}
}
public static void g(){
synchronized(o){
//do something here
}
}
}
上面f1(),f2(),f3(),g()效果一致
f1(),f2(),f3()中synchronized取得的鎖都是Test.class的鎖.
g()是自己產生一個對象o,利用o的鎖做同步
作用: 多線程中訪問此類或此類任一個實例的同步方法時都會同步. singleton模式lazily initializing屬於此類.
5. static method
class Test{
private static int v = 0;
public static void f1(){
//do something, 但函數中沒用用到v
}
public synchronized static void f2(){
//do something, 函數中對v進行了讀/寫.
}
}
多線程中使用Test的某個實列時,
(1) f1()是線程安全的,不需要同步
(2) f2()這個靜態方法中使用了函數外靜態變數,所以需要同步.
Java非同步:
1、 它要能適應不同類型的請求:
本節用 makeString來說明要求有返回值的請求.用displayString來說明不需要返回值的請求.
2、 要能同時並發處理多個請求,並能按一定機制調度:
本節將用一個隊列來存放請求,所以只能按FIFO機制調度,你可以改用LinkedList,就可以簡單實現一個優先順序(優先順序高的addFirst,低的addLast).
3、有能力將調用的邊界從線程擴展到機器間(RMI)
4、分離過度耦合,如分離調用句柄(取貨憑證)和真實數據的實現.分離調用和執行的過程,可以盡快地將調返回.
現在看具體的實現:
public interface Axman {
Result resultTest(int count,char c);
void noResultTest(String str);
}
這個介面有兩個方法要實現,就是有返回值的調用resultTest和不需要返回值的調用
noResultTest, 我們把這個介面用一個代理類來實現,目的是將方法調用轉化為對象,這樣就可以將多個請求(多個方法調)放到一個容器中緩存起來,然後統一處理,因為 Java不支持方法指針,所以把方法調用轉換為對象,然後在這個對象上統一執行它們的方法,不僅可以做到非同步處理,而且可以將代表方法調用的請求對象序列化後通過網路傳遞到另一個機器上執行(RMI).這也是Java回調機制最有力的實現.
一個簡單的例子.
如果 1: 做A
如果 2: 做B
如果 3: 做C
如果有1000個情況,你不至於用1000個case吧?以後再增加呢?
所以如果C/C++程序員,會這樣實現: (c和c++定義結構不同)
type define struct MyStruct{
int mark;
(*fn) ();
} MyList;
然後你可以聲明這個結構數據:
{1,A,
2,B
3,C
}
做一個循環:
for(i=0;i<length;i++) {
if(數據組[i].mark == 傳入的值) (數據組[i].*fn)();
}
簡單說c/c++中將要被調用的涵數可以被保存起來,然後去訪問,調用,而Java中,我們無法將一個方法保存,除了直接調用,所以將要調用的方法用子類來實現,然後把這些子類實例保存起來,然後在這些子類的實現上調用方法:
interface My{
void test();
}
『玖』 java 同步方法調用方法同步嗎
線程一 執行完上面的代碼 獲得了嗎
獲得了m1的使用權
也就是將m1加鎖
執行完了i++ 正在跑那個循環
然後這時候 線程2 也開始執行 鎖住了 obj
然後執行了 i++
線程2又開始跑循環
這時 線程一m1中的循環執行完成了 輸出了i
線程2 執行完循環輸出i
這樣的執行 線程1和2輸出的i是相等的 而且沒有線程會輸出i-1