溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JAVA中native方法與synchronized 關(guān)鍵字

發(fā)布時間:2020-08-10 11:58:46 來源:ITPUB博客 閱讀:415 作者:jasonhero 欄目:編程語言

native , synchronized

[@more@]

JAVA中native方法
@與羊共舞的狼

Java不是完美的,Java的不足除了體現(xiàn)在運行速度上要比傳統(tǒng)的C++慢許多之外,Java無法直接訪問到操

作系統(tǒng)底層(如系統(tǒng)硬件等),為此Java使用native方法來擴展Java程序的功能。
  可以將native方法比作Java程序同C程序的接口,其實現(xiàn)步驟:
  1、在Java中聲明native()方法,然后編譯;
 ?。病⒂胘avah產(chǎn)生一個.h文件;
 ?。场懸粋€.cpp文件實現(xiàn)native導(dǎo)出方法,其中需要包含第二步產(chǎn)生的.h文件(注意其中又包含了

JDK帶的jni.h文件);
 ?。础⒌谌降?cpp文件編譯成動態(tài)鏈接庫文件;
  5、在Java中用System.loadLibrary()方法加載第四步產(chǎn)生的動態(tài)鏈接庫文件,這個native()方法就

可以在Java中被訪問了。

JAVA本地方法適用的情況 1.為了使用底層的主機平臺的某個特性,而這個特性不能通過JAVA API訪問

2.為了訪問一個老的系統(tǒng)或者使用一個已有的庫,而這個系統(tǒng)或這個庫不是用JAVA編寫的

3.為了加快程序的性能,而將一段時間敏感的代碼作為本地方法實現(xiàn)。

首先寫好JAVA文件
/*
* Created on 2005-12-19 Author shaoqi
*/
package com.hode.hodeframework.modelupdate;

public class CheckFile
{
public native void displayHelloWorld();

static
{
System.loadLibrary("test");
}

public static void main(String[] args) {
new CheckFile().displayHelloWorld();
}
}
然后根據(jù)寫好的文件編譯成CLASS文件
然后在classes或bin之類的class根目錄下執(zhí)行javah -jni

com.hode.hodeframework.modelupdate.CheckFile,
就會在根目錄下得到一個com_hode_hodeframework_modelupdate_CheckFile.h的文件
然后根據(jù)頭文件的內(nèi)容編寫com_hode_hodeframework_modelupdate_CheckFile.c文件
#include "CheckFile.h"
#include
#include

JNIEXPORT void JNICALL Java_com_hode_hodeframework_modelupdate_CheckFile_displayHelloWorld

(JNIEnv *env, jobject obj)
{
printf("Hello world!n");
return;
}
之后編譯生成DLL文件如“test.dll”,名稱與System.loadLibrary("test")中的名稱一致
vc的編譯方法:cl -I%java_home%include -I%java_home%includewin32 -LD

com_hode_hodeframework_modelupdate_CheckFile.c -Fetest.dll
最后在運行時加參數(shù)-Djava.library.path=[dll存放的路徑]

********************************************************************************************

synchronized 關(guān)鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
1. synchronized 方法:通過在方法聲明中加入 synchronized關(guān)鍵字來聲明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制對類成員變量的訪問:每個類實例對應(yīng)一把鎖,每個 synchronized 方法都必須

獲得調(diào)用該方法的類實例的鎖方能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行,就獨占該鎖,直到從該方法

返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執(zhí)行狀態(tài)。這種機制確保了同一時刻對

于每一個類實例,其所有聲明為 synchronized 的成員函數(shù)中至多只有一個處于可執(zhí)行狀態(tài)(因為至多只

有一個能夠獲得該類實例對應(yīng)的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員

變量的方法均被聲明為 synchronized)。
在 Java 中,不光是類實例,每一個類也對應(yīng)一把鎖,這樣我們也可將類的靜態(tài)成員函數(shù)聲明為

synchronized ,以控制其對類的靜態(tài)成員變量的訪問。
synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線

程類的方法 run() 聲明為 synchronized ,由于在線程的整個生命期內(nèi)它一直在運行,因此將導(dǎo)致它對

本類任何 synchronized 方法的調(diào)用都永遠不會成功。當然我們可以通過將訪問類成員變量的代碼放到專

門的方法中,將其聲明為 synchronized ,并在主方法中調(diào)用來解決這一問題,但是 Java 為我們提供了

更好的解決辦法,那就是 synchronized 塊。
2. synchronized 塊:通過 synchronized關(guān)鍵字來聲明synchronized 塊。語法如下:
synchronized(syncObject) {
//允許訪問控制的代碼
}
synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例

或類)的鎖方能執(zhí)行,具體機制同前所述。由于可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活

性較高。

對synchronized(this)的一些理解(很細致,感謝作者?。?/p>

一、當兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能

有一個線程得到執(zhí)行。另一個線程必須等待當前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。

二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該

object中的非synchronized(this)同步代碼塊。

三、尤其關(guān)鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object

中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)

同步代碼塊時,它就獲得了這個object的對象鎖。結(jié)果,其它線程對該object對象所有同步代碼部分的訪

問都被暫時阻塞。

五、以上規(guī)則對其它對象鎖同樣適用.

舉例說明:
一、當兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能

有一個線程得到執(zhí)行。另一個線程必須等待當前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。

package ths;

public class Thread1 implements Runnable {
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}

結(jié)果:
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4

二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該

object中的非synchronized(this)同步代碼塊。

package ths;

public class Thread2 {
public void m4t1() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
public void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
public static void main(String[] args) {
final Thread2 myt2 = new Thread2();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt2.m4t1();
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
myt2.m4t2();
}
}, "t2"
);
t1.start();
t2.start();
}
}

結(jié)果:
t1 : 4
t2 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t1 : 1
t2 : 1
t1 : 0
t2 : 0

三、尤其關(guān)鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object

中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

//修改Thread2.m4t2()方法:
public void m4t2() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}

}

結(jié)果:

t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)

同步代碼塊時,它就獲得了這個object的對象鎖。結(jié)果,其它線程對該object對象所有同步代碼部分的訪

問都被暫時阻塞。

//修改Thread2.m4t2()方法如下:

public synchronized void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}

結(jié)果:
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

五、以上規(guī)則對其它對象鎖同樣適用:

package ths;

public class Thread3 {
class Inner {
private void m4t1() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
private void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
}
private void m4t1(Inner inner) {
synchronized(inner) { //使用對象鎖
inner.m4t1();
}
}
private void m4t2(Inner inner) {
inner.m4t2();
}
public static void main(String[] args) {
final Thread3 myt3 = new Thread3();
final Inner inner = myt3.new Inner();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt3.m4t1(inner);
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
myt3.m4t2(inner);
}
}, "t2"
);
t1.start();
t2.start();
}
}

結(jié)果:

盡管線程t1獲得了對Inner的對象鎖,但由于線程t2訪問的是同一個Inner中的非同步部分。所以兩個線程

互不干擾。

t1 : Inner.m4t1()=4
t2 : Inner.m4t2()=4
t1 : Inner.m4t1()=3
t2 : Inner.m4t2()=3
t1 : Inner.m4t1()=2
t2 : Inner.m4t2()=2
t1 : Inner.m4t1()=1
t2 : Inner.m4t2()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=0

現(xiàn)在在Inner.m4t2()前面加上synchronized:

private synchronized void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}

結(jié)果:

盡管線程t1與t2訪問了同一個Inner對象中兩個毫不相關(guān)的部分,但因為t1先獲得了對Inner的對象鎖,所

以t2對Inner.m4t2()的訪問也被阻塞,因為m4t2()是Inner中的一個同步方法。

t1 : Inner.m4t1()=4
t1 : Inner.m4t1()=3
t1 : Inner.m4t1()=2
t1 : Inner.m4t1()=1
t1 : Inner.m4t1()=0
t2 : Inner.m4t2()=4
t2 : Inner.m4t2()=3
t2 : Inner.m4t2()=2
t2 : Inner.m4t2()=1
t2 : Inner.m4t2()=0


-----------------------------------------------------------------------------

2。 Java線程及同步(synchronized)樣例代碼

import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;

public class TestThread extends Thread
{
private static Integer threadCounterLock; //用于同步,防止數(shù)據(jù)被寫亂
private static int threadCount; //本類的線程計數(shù)器

static
{
threadCount = 0;
threadCounterLock = new Integer(0);
}

public TestThread()
{
super();
}

public synchronized static void incThreadCount()
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}

public synchronized static void decThreadCount()
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}

public void run()
{
synchronized(threadCounterLock) //同步
{
threadCount++;
System.out.println("thread count after enter: " + threadCount);
}

//incThreadCount(); //和上面的語句塊是等價的

final long nSleepMilliSecs = 1000; //循環(huán)中的休眠時間

long nCurrentTime = System.currentTimeMillis();
long nEndTime = nCurrentTime + 30000; //運行截止時間
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

try
{
while (nCurrentTime < nEndTime)
{
nCurrentTime = System.currentTimeMillis();
System.out.println("Thread " + this.hashCode() + ", current time: " +

simpleDateFormat.format(new Date(nCurrentTime)));

try
{
sleep(nSleepMilliSecs);
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
}
finally
{
synchronized(threadCounterLock) //同步
{
threadCount--;
System.out.println("thread count after leave: " + threadCount);
}

//decThreadCount(); //和上面的語句塊是等價的
}
}

public static void main(String[] args)
{
TestThread[] testThread = new TestThread[2];
for (int i=0; i{
testThread[i] = new TestThread();
testThread[i].start();
}
}
}

同步就是簡單的說我用的時候你不能用,大家用的要是一樣的就這樣!
比如說有只蘋果很好吃,我拉起來咬一口,放下,你再拉起咬一口,這就同步了,要是大家一起咬,呵呵

,那就結(jié)婚吧,婚禮上常能看到這個,也不怕咬著嘴,嘻嘻嘻!

舉個例子,現(xiàn)在有個類,類中有一個私有成員一個蘋果,兩個方法一個看,一個吃。
現(xiàn)在不同步,我一“看”,哈哈一個蘋果,我“吃”四分之一了
你一“看”,哈哈一個蘋果,也“吃”四分之一了。
可能的情況就是都是看到一個蘋果但我的吃方法用在你的之前,所以可能你只能吃到3/4的1/4也就是3/16

個而不是1/4個蘋果了。
現(xiàn)在加入同步鎖,我在吃的時候你看被鎖,等吃完了,你再看,啊3/4個蘋果,吃1/3好了了,就這樣!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI