Java靜態(tài)方法是使用公共內(nèi)存空間的,就是說所有對(duì)象都可以引用,而且在沒有創(chuàng)建對(duì)象時(shí)也可以利用類使用該方法。
例如,我創(chuàng)建一個(gè)類,里面有一個(gè)靜態(tài)方法:
class Test{
public static int z(int xx,int yy){
return xx+yy;
}
public int zz(int xx,int yy){
return xx+yy;
}
}
然后在含有main方法的類中使用這個(gè)類時(shí),對(duì)與以上非靜態(tài)和靜態(tài)方法的引用方式是不同的,如下:
import Test;
public class mainClass{
int sum;
public static void main(String args[]){
sum=Test.z(1,2); //直接用 類.方法或者屬性就可以使用該方法或?qū)傩浴?
System.out.println(sum);
Test t=new Test();
sum=t.zz(1,2); //因?yàn)閦z不是靜態(tài)方法,所以只能只能用Test類創(chuàng)建一個(gè)t對(duì)象,然后調(diào)用該對(duì)象的方法。
System.out.println(sum);
}
}
靜態(tài)方法可以調(diào)用靜態(tài)方法,但不能調(diào)用成員方法。
wait():使一個(gè)線程處于等待狀態(tài),并且釋放所持有的對(duì)象的lock。
sleep():使一個(gè)正在運(yùn)知行的線程處于睡眠狀態(tài),是一個(gè)靜態(tài)方法,調(diào)用此道方法要捕捉InterruptedException異常。
notify():?jiǎn)拘岩粋€(gè)處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時(shí)候,并不專能確切的喚醒某一個(gè)等待狀態(tài)的線程,而是由JVM確定喚醒哪個(gè)線程,而且不是按優(yōu)先級(jí)。
Allnotity():?jiǎn)拘阉刑幦氲却隣顟B(tài)的線程,注意并不是給所有喚醒線程一個(gè)對(duì)象的鎖,而是讓屬它們競(jìng)爭(zhēng)。
靜態(tài)方法、靜態(tài)變量,方便了開發(fā)中的操作,不需要實(shí)例則可以調(diào)用,但是往往卻破壞了一些屬性的封裝,使得在安全性方面大大降低,在內(nèi)存使用上和實(shí)例變量有著不同的地方,靜態(tài)變量或方法他是在程序一運(yùn)行類一加載的時(shí)候就會(huì)為他分配了一塊內(nèi)存地址,相當(dāng)于初始化了這些靜態(tài)變量,而實(shí)例變量或?qū)傩允侵挥挟?dāng)對(duì)象被實(shí)例的時(shí)候才會(huì)為這些屬性分配地址,也就是說在程序運(yùn)行的時(shí)候,如果是小程序,那么在使用過程中占用的內(nèi)存會(huì)隨著你實(shí)例的創(chuàng)建而逐步增加,對(duì)象需要被共享的時(shí)候,這時(shí)候可以考慮單例模式(只有一個(gè)實(shí)例),保證不會(huì)浪費(fèi)內(nèi)存地址,當(dāng)然這要符合實(shí)際,但是如果是一個(gè)比較大的項(xiàng)目,重用性強(qiáng),變量需要被共享的時(shí)候,就可以考慮用static來解決。
可以多多交流哦 交流群:45271133。
總的結(jié)論:java是線程安全的,即對(duì)任何方法(包括靜態(tài)方法)都可以不考慮線程沖突,但有一個(gè)前提,就是不能存在全局變量。如果存在全局變量,則需要使用同步機(jī)制。
如下通過一組對(duì)比例子從頭講解:
在多線程中使用靜態(tài)方法會(huì)發(fā)生什么事?也就是說多線程訪問同一個(gè)類的static靜態(tài)方法會(huì)發(fā)生什么事?是否會(huì)發(fā)生線程安全問題?
public class Test {
public static void operation(){
// 。 do something
}
}
事實(shí)證明只要在靜態(tài)函數(shù)中沒有處理多線程共享數(shù)據(jù),就不存在著多線程訪問同一個(gè)靜態(tài)方法會(huì)出現(xiàn)資源沖突的問題。下面看一個(gè)例子:
public class StaticThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
StaticAction.print();
}
public static void main(String[] args) {
for (int i = 0; i
在java5以前實(shí)現(xiàn)多線程有兩種方法(繼承Thread類和實(shí)現(xiàn)Runnable接口)
它們分別為:
使用new Thread()和new Thread(Runnable)形式
第一種直接調(diào)用thread的run方法,所以,往往使用Thread子類,即new SubThread()。
第二種調(diào)用
Runnable的run方法。
第一種:
new Thread(){}.start();這表示調(diào)用Thread子類對(duì)象的run方法,new Thread(){}表示一個(gè)Thread的匿名子類的實(shí)例對(duì)象,子類加上run方法后的代碼如下:
new Thread(){
public void run(){
}
}.start();
第二種:
new Thread(
new Runnable(){}
).start();
這表示調(diào)用Thread對(duì)象接受的Runnable對(duì)象的run方法,new Runnable(){}表示一個(gè)Runnable的匿名子類的實(shí)例對(duì)象,
runnable的子類加上run方法后的代碼如下:
new Thread(new Runnable(){
public void run(){
}
}
).start();
類的成員分為兩類,靜態(tài)成員(static member)和實(shí)例成員(instance member)。靜態(tài)成員屬于類,實(shí)例成員則屬于對(duì)象,即類的實(shí)例。
簡(jiǎn)單討論一下在一個(gè)類中使用靜態(tài)字段(static field)和靜態(tài)方法(static method)是否會(huì)有線程安全問題。
我們?cè)谥溃?靜態(tài)字段(static field)和靜態(tài)方法(static method)的調(diào)用是通過類來調(diào)用。靜態(tài)方法不對(duì)特定的實(shí)例操作,只能訪問靜態(tài)成員。實(shí)例方法可對(duì)特定的實(shí)例操作,既能訪問靜態(tài)成員,也能訪問實(shí)例成員。
那么,在多線程中使用靜態(tài)方法是否有線程安全問題?這要看靜態(tài)方法是是引起線程安全問題要看在靜態(tài)方法中是否使用了靜態(tài)成員。
因?yàn)椋诙嗑€程中使用同一個(gè)靜態(tài)方法時(shí),每個(gè)線程使用各自的實(shí)例字段(instance field)的副本,而共享一個(gè)靜態(tài)字段(static field)。所以說,如果該靜態(tài)方法不去操作一個(gè)靜態(tài)成員,只在方法內(nèi)部使用實(shí)例字段(instance field),不會(huì)引起安全性問題。但是,如果該靜態(tài)方法操作了一個(gè)靜態(tài)字段,則需要靜態(tài)方法中采用互斥訪問的方式進(jìn)行安全處理。
舉個(gè)簡(jiǎn)單的例子,我們使用的Console.WriteLine();中WriteLine()是Console.WriteLine類的靜態(tài)方法。
對(duì)于ASP.NET, 多個(gè)客戶端訪問服務(wù)器端, 這是一個(gè)多線程的例子.只要理解了原因,我們可以在三層架構(gòu)中的數(shù)據(jù)訪問層中放心使用靜態(tài)方法(static method)來訪問數(shù)據(jù)庫.
先看一個(gè)類:
public class Test
{
public static String hello(String str)
{
String tmp = "";
tmp = tmp + str;
return tmp;
}
}
hello方法會(huì)不會(huì)有多線程安全問題呢?沒有!
靜態(tài)方法如果沒有使用靜態(tài)變量,則沒有線程安全問題。
為什么呢?因?yàn)殪o態(tài)方法內(nèi)聲明的變量,每個(gè)線程調(diào)用時(shí),都會(huì)新創(chuàng)建一份,而不會(huì)共用一個(gè)存儲(chǔ)單元。比如這里的tmp,每個(gè)線程都會(huì)創(chuàng)建自己的一份,因此不會(huì)有線程安全問題。
注意:靜態(tài)變量,由于是在類加載時(shí)占用一個(gè)存儲(chǔ)區(qū),每個(gè)線程都是共用這個(gè)存儲(chǔ)區(qū)的,所以如果在靜態(tài)方法里使用了靜態(tài)變量,這就會(huì)有線程安全問題!
這要看靜態(tài)方法中有沒有操作靜態(tài)成員變量了,看代碼吧
public class StaticMethod implements Runnable {
static int num=0;
public static void addOne() throws InterruptedException {
for (int i = 0; i <= 10; i++) {
num += i;
}
System.out.println(Thread.currentThread().getName() + "-" + num);
num=0;
}
}如上面代碼所示,當(dāng)單線程運(yùn)行情況下是輸出正常的,num最后應(yīng)該輸出55,但是在多線程情況下,則會(huì)出現(xiàn)每個(gè)線程輸出的num不一樣的情況,這是因?yàn)閚um是靜態(tài)成員變量,為多個(gè)線程所共享的,有可能會(huì)出現(xiàn)一個(gè)線程的num值還沒有重新賦值為0,另外一個(gè)線程已經(jīng)讀取到num的累加后的值,所以說,多線程情況下,靜態(tài)方法中如果操作靜態(tài)成員變量,那這個(gè)靜態(tài)方法就不是線程安全的
聲明:本網(wǎng)站尊重并保護(hù)知識(shí)產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護(hù)條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請(qǐng)?jiān)谝粋€(gè)月內(nèi)通知我們,我們會(huì)及時(shí)刪除。
蜀ICP備2020033479號(hào)-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時(shí)間:2.468秒