ThreadLocal
類是悄悄地出現在 Java 平臺版本 1.2 中的。雖然支持線程局部變量早就是許多線程工具(例如 Posixpthreads
工具)的一部分,但 Java Threads API 的最初設計卻沒有這項有用的功能。而且,最初的實現也相當低效。由于這些原因,ThreadLocal
極少受到關注,但對簡化線程安全并發程序的開發來說,它卻是很方便的。在 輕松使用線程的第 3 部分,Java 軟件顧問 Brian Goetz 研究了ThreadLocal
并提供了一些使用技巧。參加 Brian 的 多線程 Java 編程討論論壇以獲得您工程中的線程和并發問題的幫助。
編寫線程安全類是困難的。它不但要求仔細分析在什么條件可以對變量進行讀寫,而且要求仔細分析其它類能如何使用某個類。 有時,要在不影響類的功能、易用性或性能的情況下使類成為線程安全的是很困難的。有些類保留從一個方法調用到下一個方法調用的狀態信息,要在實踐中使這樣的類成為線程安全的是困難的。
管理非線程安全類的使用比試圖使類成為線程安全的要更容易些。非線程安全類通常可以安全地在多線程程序中使用,只要您能確保一個線程所用的類的實例不被其它線程使用。例如,JDBC Connection
類是非線程安全的 — 兩個線程不能在小粒度級上安全地共享一個 Connection
— 但如果每個線程都有它自己的 Connection
,那么多個線程就可以同時安全地進行數據庫操作。
不使用 ThreadLocal
為每個線程維護一個單獨的 JDBC 連接(或任何其它對象)當然是可能的;Thread API 給了我們把對象和線程聯系起來所需的所有工具。而 ThreadLocal 則使我們能更容易地把線程和它的每線程(per-thread)數據成功地聯系起來。
什么是線程局部變量(thread-local variable)?
線程局部變量高效地為每個使用它的線程提供單獨的線程局部變量值的副本。每個線程只能看到與自己相聯系的值,而不知道別的線程可能正在使用或修改它們自己的副本。一些編譯器(例如 Microsoft Visual C++ 編譯器或 IBM XL FORTRAN 編譯器)用存儲類別修飾符(像 static
或 volatile
)把對線程局部變量的支持集成到了其語言中。Java 編譯器對線程局部變量不提供特別的語言支持;相反地,它用 ThreadLocal
類實現這些支持, 核心 Thread
類中有這個類的特別支持。
因為線程局部變量是通過一個類來實現的,而不是作為 Java 語言本身的一部分,所以 Java 語言線程局部變量的使用語法比內建線程局部變量語言的使用語法要笨拙一些。要創建一個線程局部變量,請實例化類 ThreadLocal
的一個對象。 ThreadLocal
類的行為與 java.lang.ref
中的各種 Reference
類的行為很相似; ThreadLocal
類充當存儲或檢索一個值時的間接句柄。清單 1 顯示了 ThreadLocal
接口。
|
get()
訪問器檢索變量的當前線程的值; set()
訪問器修改當前線程的值。 initialValue()
方法是可選的,如果線程未使用過某個變量,那么您可以用這個方法來設置這個變量的初始值;它允許延遲初始化。用一個示例實現來說明 ThreadLocal 的工作方式是最好的方法。清單 2 顯示了 ThreadLocal
的一個實現方式。它不是一個特別好的實現(雖然它與最初實現非常相似),所以很可能性能不佳,但它清楚地說明了 ThreadLocal 的工作方式。
|
這個實現的性能不會很好,因為每個 get()
和 set()
操作都需要 values
映射表上的同步,而且如果多個線程同時訪問同一個 ThreadLocal
,那么將發生爭用。此外,這個實現也是不切實際的,因為用 Thread
對象做 values
映射表中的關鍵字將導致無法在線程退出后對 Thread
進行垃圾回收,而且也無法對死線程的 ThreadLocal
的特定于線程的值進行垃圾回收。
![]() ![]() |
![]()
|
線程局部變量常被用來描繪有狀態“單子”(Singleton) 或線程安全的共享對象,或者是通過把不安全的整個變量封裝進 ThreadLocal
,或者是通過把對象的特定于線程的狀態封裝進 ThreadLocal
。例如,在與數據庫有緊密聯系的應用程序中,程序的很多方法可能都需要訪問數據庫。在系統的每個方法中都包含一個 Connection
作為參數是不方便的 — 用“單子”來訪問連接可能是一個雖然更粗糙,但卻方便得多的技術。然而,多個線程不能安全地共享一個 JDBC Connection
。如清單 3 所示,通過使用“單子”中的 ThreadLocal
,我們就能讓我們的程序中的任何類容易地獲取每線程 Connection
的一個引用。這樣,我們可以認為 ThreadLocal
允許我們創建 每線程單子。
|
任何創建的花費比使用的花費相對昂貴些的有狀態或非線程安全的對象,例如 JDBC Connection
或正則表達式匹配器,都是可以使用每線程單子(singleton)技術的好地方。當然,在類似這樣的地方,您可以使用其它技術,例如用池,來安全地管理共享訪問。然而,從可伸縮性角度看,即使是用池也存在一些潛在缺陷。因為池實現必須使用同步,以維護池數據結構的完整性,如果所有線程使用同一個池,那么在有很多線程頻繁地對池進行訪問的系統中,程序性能將因爭用而降低。
![]() ![]() |
![]()
|
其它適合使用 ThreadLocal
但用池卻不能成為很好的替代技術的應用程序包括存儲或累積每線程上下文信息以備稍后檢索之用這樣的應用程序。例如,假設您想創建一個用于管理多線程應用程序調試信息的工具。您可以用如清單 4 所示的 DebugLogger
類作為線程局部容器來累積調試信息。在一個工作單元的開頭,您清空容器,而當一個錯誤出現時,您查詢該容器以檢索這個工作單元迄今為止生成的所有調試信息。
|
在您的代碼中,您可以調用 DebugLogger.put()
來保存您的程序正在做什么的信息,而且,稍后如果有必要(例如發生了一個錯誤),您能夠容易地檢索與某個特定線程相關的調試信息。 與簡單地把所有信息轉儲到一個日志文件,然后努力找出哪個日志記錄來自哪個線程(還要擔心線程爭用日志紀錄對象)相比,這種技術簡便得多,也有效得多。
ThreadLocal
在基于 servlet 的應用程序或工作單元是一個整體請求的任何多線程應用程序服務器中也是很有用的,因為在處理請求的整個過程中將要用到單個線程。您可以通過前面講述的每線程單子技術用 ThreadLocal
變量來存儲各種每請求(per-request)上下文信息。
![]() ![]() |
![]()
|
ThreadLocal 的線程安全性稍差的堂兄弟,InheritableThreadLocal
ThreadLocal 類有一個親戚,InheritableThreadLocal,它以相似的方式工作,但適用于種類完全不同的應用程序。創建一個線程時如果保存了所有 InheritableThreadLocal
對象的值,那么這些值也將自動傳遞給子線程。如果一個子線程調用 InheritableThreadLocal
的 get()
,那么它將與它的父線程看到同一個對象。為保護線程安全性,您應該只對不可變對象(一旦創建,其狀態就永遠不會被改變的對象)使用 InheritableThreadLocal
,因為對象被多個線程共享。 InheritableThreadLocal
很合適用于把數據從父線程傳到子線程,例如用戶標識(user id)或事務標識(transaction id),但不能是有狀態對象,例如 JDBC Connection
。
![]() ![]() |
![]()
|
雖然線程局部變量早已赫赫有名并被包括 Posix pthreads
規范在內的很多線程框架支持,但最初的 Java 線程設計中卻省略了它,只是在 Java 平臺的版本 1.2 中才添加上去。在很多方面, ThreadLocal
仍在發展之中;在版本 1.3 中它被重寫,版本 1.4 中又重寫了一次,兩次都專門是為了性能問題。
在 JDK 1.2 中, ThreadLocal
的實現方式與清單 2 中的方式非常相似,除了用同步 WeakHashMap
代替 HashMap
來存儲 values 之外。(以一些額外的性能開銷為代價,使用 WeakHashMap 解決了無法對 Thread 對象進行垃圾回收的問題。)不用說, ThreadLocal
的性能是相當差的。
Java 平臺版本 1.3 提供的 ThreadLocal
版本已經盡量更好了;它不使用任何同步,從而不存在可伸縮性問題,而且它也不使用弱引用。相反地,人們通過給 Thread
添加一個實例變量(該變量用于保存當前線程的從線程局部變量到它的值的映射的 HashMap
)來修改 Thread
類以支持 ThreadLocal
。因為檢索或設置一個線程局部變量的過程不涉及對可能被另一個線程讀寫的數據的讀寫操作,所以您可以不用任何同步就實現 ThreadLocal.get()
和 set()
。而且,因為每線程值的引用被存儲在自已的 Thread
對象中,所以當對 Thread
進行垃圾回收時,也能對該 Thread
的每線程值進行垃圾回收。
不幸的是,即使有了這些改進,Java 1.3 中的 ThreadLocal
的性能仍然出奇地慢。據我的粗略測量,在雙處理器 Linux 系統上的 Sun 1.3 JDK 中進行 ThreadLocal.get()
操作,所耗費的時間大約是無爭用同步的兩倍。性能這么差的原因是 Thread.currentThread()
方法的花費非常大,占了 ThreadLocal.get()
運行時間的三分之二還多。雖然有這些缺點,JDK 1.3 ThreadLocal.get()
仍然比爭用同步快得多,所以如果在任何存在嚴重爭用的地方(可能是有非常多的線程,或者同步塊被頻繁地執行,或者同步塊很大), ThreadLocal
可能仍然要高效得多。
在 Java 平臺的最新版本,即版本 1.4b2 中, ThreadLocal
和 Thread.currentThread()
的性能都有了很大提高。有了這些提高, ThreadLocal
應該比其它技術,如用池,更快。由于它比其它技術更簡單,也更不易出錯,人們最終將發現它是避免線程間出現不希望的交互的有效途徑。
![]() ![]() |
![]()
|
ThreadLocal
能帶來很多好處。它常常是把有狀態類描繪成線程安全的,或者封裝非線程安全類以使它們能夠在多線程環境中安全地使用的最容易的方式。使用 ThreadLocal
使我們可以繞過為實現線程安全而對何時需要同步進行判斷的復雜過程,而且因為它不需要任何同步,所以也改善了可伸縮性。除簡單之外,用 ThreadLocal
存儲每線程單子或每線程上下文信息在歸檔方面還有一個頗有價值好處 — 通過使用 ThreadLocal
,存儲在 ThreadLocal
中的對象都是 不被線程共享的是清晰的,從而簡化了判斷一個類是否線程安全的工作。
我希望您從這個系列中得到了樂趣,也學到了知識,我也鼓勵您到我的 討論論壇中來深入研究多線程問題。
Servlet是在多線程環境下的。即可能有多個請求發給一個servelt實例,每個請求是一個線程。
struts下的action也類似,同樣在多線程環境下。可以參考struts user guide: http://struts.apache.org/struts-action/userGuide/building_controller.html 中的Action Class Design Guidelines一節: Write code for a multi-threaded environment - Our controller servlet creates only one instance of your Action class, and uses this one instance to service all requests. Thus, you need to write thread-safe Action classes. Follow the same guidelines you would use to write thread-safe Servlets.
譯:為多線程環境編寫代碼。我們的controller servlet指揮創建你的Action 類的一個實例,用此實例來服務所有的請求。因此,你必須編寫線程安全的Action類。遵循與寫線程安全的servlet同樣的方針。
1.什么是線程安全的代碼
在多線程環境下能正確執行的代碼就是線程安全的。
安全的意思是能正確執行,否則后果是程序執行錯誤,可能出現各種異常情況。
2.如何編寫線程安全的代碼
很多書籍里都詳細講解了如何這方面的問題,他們主要講解的是如何同步線程對共享資源的使用的問題。主要是對synchronized關鍵字的各種用法,以及鎖的概念。
Java1.5中也提供了如讀寫鎖這類的工具類。這些都需要較高的技巧,而且相對難于調試。
但是,線程同步是不得以的方法,是比較復雜的,而且會帶來性能的損失。等效的代碼中,不需要同步在編寫容易度和性能上會更好些。
我這里強調的是什么代碼是始終為線程安全的、是不需要同步的。如下:
1)常量始終是線程安全的,因為只存在讀操作。
2)對構造器的訪問(new 操作)是線程安全的,因為每次都新建一個實例,不會訪問共享的資源。
3)最重要的是:局部變量是線程安全的。因為每執行一個方法,都會在獨立的空間創建局部變量,它不是共享的資源。局部變量包括方法的參數變量。
struts user guide里有:
Only Use Local Variables - The most important principle that aids in thread-safe coding is to use only local variables, not instance variables , in your Action class.
譯:只使用用局部變量。--編寫線程安全的代碼最重要的原則就是,在Action類中只使用局部變量,不使用實例變量。
總結:
在Java的Web服務器環境下開發,要注意線程安全的問題。最簡單的實現方式就是在Servlet和Struts Action里不要使用類變量、實例變量,但可以使用類常量和實例常量。
如果有這些變量,可以將它們轉換為方法的參數傳入,以消除它們。
注意一個容易混淆的地方:被Servlet或Action調用的類中(如值對象、領域模型類)中是否可以安全的使用實例變量?如果你在每次方法調用時
新建一個對象,再調用它們的方法,則不存在同步問題---因為它們不是多個線程共享的資源,只有共享的資源才需要同步---而Servlet和Action的實例對于多個線程是共享的。
換句話說,Servlet和Action的實例會被多個線程同時調用,而過了這一層,如果在你自己的代碼中沒有另外啟動線程,且每次調用后續業務對象時都是先新建一個實例再調用,則都是線程安全的。
CSS全稱Cascading Style Sheet。層疊式樣式表。從三年前就開始使用CSS了,但一直以來都小看了它。CSS的出現其實是一次革命,它試圖將網站的內容與表現分開。 2.外鏈式: 3.導入式 3.屬性式: #fontRed 注明兩點 CSS 標簽屬性/屬性參考 CSS 標簽屬性/屬性 行為屬性 behavior 字體和文本屬性 direction* direction 顏色和背景屬性 background-attachment 版面屬性 border 分類屬性 display list-style 定位屬性 bottom* clip 打印屬性 page** pageBreakAfter 濾鏡屬性 filter 偽類和其它屬性 :active @charset 我們知道Dreamweaver在表格制作方面做得非常出色,但是在某些時候還是必須結合css才能達到一些特定效果,下面我們先把有關表格邊框的css語法整理出來,然后另外介紹怎樣用css美化表格的邊框。 有關表格邊框的css語法 具體內容包括:上邊框寬度、右邊框寬度、下邊框寬度、左邊框寬度、邊框寬度、邊框顏色、邊框樣式、上邊框、下邊框、左邊框、右邊框、邊框、寬度、高度、有關標簽等。 1.上邊框寬度 語法: border-top-width: <值> 允許值: thin | medium | thick | <長度> 初始值: medium 適用于: 所有對象 向下兼容: 否 上邊框寬度屬性用于指定一個元素上邊框的寬度。值可以是三個關鍵字其中的一個,都不受字體大小或長度的影響,可以用于實現成比例的寬度。不允許使用負值。也可以用在上邊框、邊框的寬度或邊框的屬性略寫。 2.右邊框寬度 語法: border-right-width: <值> 允許值: thin | medium | thick | <長度> 初始值: medium 適用于: 所有對象 向下兼容: 否 右邊框寬度屬性用于指定元素的右邊框的寬度。值可以是三個關鍵字其中的一個,都不受字體大小或長度的影響,可以用于實現成比例的寬度。不允許使用負值。也可以用在右邊框、邊框的寬度或邊框的屬性略寫。 3.下邊框寬度 語法: border-bottom-width: <值> 允許值: thin | medium | thick | <長度> 初始值: medium 適用于: 所有對象 向下兼容: 否 下邊框寬度屬性用于指定元素的下邊框的寬度。值可以是三個關鍵字其中的一個,都不受字體大小或長度的影響,可以用于實現成比例的寬度。不允許使用負值。也可以用在下邊框、邊框的寬度或邊框的屬性略寫。 4.左邊框寬度 語法: border-left-width: <值> 允許值: thin | medium | thick | <長度> 初始值: medium 適用于: 所有對象 向下兼容: 否 左邊框寬度屬性用于指定元素的左邊框的寬度。值可以是三個關鍵字其中的一個,都不受字體大小或長度的影響,可以用于實現成比例的寬度。不允許使用負值。也可以用在左邊框、邊框的寬度或邊框的屬性略寫。 5.邊框寬度 語法: border-width: <值> 允許值: [ thin | medium | thick | <長度> ]{1,4} 初始值: 未定義 適用于: 所有對象 向下兼容: 否 邊框寬度屬性用一到四個值來設置元素的邊界,值是一個關鍵字或長度。不允許使用負值長度。如果四個值都給出了,它們分別應用于上、右、下和左邊框的式樣。如果給出一個值,它將被運用到各邊上。如果兩個或三個值給出了,省略了的值與對邊相等。 這個屬性是上邊框寬度、右邊框寬度、下邊框寬度和左邊框寬度屬性的略寫。也可以使用略寫的邊框屬性。 6.邊框顏色 語法: border-color: <值> 允許值: <顏色>{1,4} 初始值: 顏色屬性的值 適用于: 所有對象 向下兼容: 否 邊框顏色屬性設置一個元素的邊框顏色。可以使用一到四個關鍵字。如果四個值都給出了,它們分別應用于上、右、下和左邊框的式樣。如果給出一個值,它將被運用到各邊上。如果兩個或三個值給出了,省略了的值與對邊相等。也可以使用略寫的邊框屬性。 7.邊框樣式 語法: border-style: <值> 允許值: [ none | dotted | dashed | solid | double | groove | ridge | inset | outset ]{1,4} 初始值: none 適用于: 所有對象 向下兼容: 否 邊框樣式屬性用于設置一個元素邊框的樣式。這個屬性必須用于指定可見的邊框。可以使用一到四個關鍵字。如果四個值都給出了,它們分別應用于上、右、下和左邊框的式樣。如果給出一個值,它將被運用到各邊上。如果兩個或三個值給出了,省略了的值與對邊相等。也可以使用略寫的邊框屬性。 none:無樣式; 語法: border-top: <值> 允許值: <上邊框寬度> || <邊框式樣> || <顏色> 初始值: 未定義 適用于: 所有對象 向下兼容: 否 上邊框屬性是一個用于設置一個元素上邊框的寬度、式樣和顏色的略寫。注意只能給出一個邊框式樣。也可以使用略寫的邊框屬性。 9.右邊框 語法: border-right: <值> 允許值: <右邊框寬度> || <邊框式樣> || <顏色> 初始值: 未定義 適用于: 所有對象 向下兼容: 否 右邊框屬性是一個用于設置一個元素右邊框的寬度、式樣、和顏色的略寫。注意只能給出一個邊框式樣。也可以使用略寫的邊框屬性。 10.下邊框 語法: border-bottom: <值> 允許值: <下邊框寬度> || <邊框式樣> || <顏色> 初始值: 未定義 適用于: 所有對象 向下兼容: 否 下邊框屬性是一個用于設置一個元素的下邊框的寬度、式樣和顏色的略寫。注意只能給出一個邊框式樣。也可以使用略寫的邊框屬性。 11.左邊框 語法: border-left: <值> 允許值: <左邊框寬度> || <邊框式樣> || <顏色> 初始值: 未定義 適用于: 所有對象 向下兼容: 否 左邊框屬性是一個用于設置一個元素左邊框的寬度、式樣和顏色的略寫。注意只能給出一個邊框式樣。也可以使用略寫的邊框屬性。 12.邊框 語法: border: <值> 允許值: <邊框寬度> || <邊框式樣> || <顏色> 初始值: 未定義 適用于: 所有對象 向下兼容: 否 邊框屬性是一個用于設置一個元素邊框的寬度、式樣和顏色的略寫。 邊框聲明的例子包括: H2 { border: groove 3em } 邊框屬性只能設置四種邊框;只能給出一組邊框的寬度和式樣。為了給出一個元素的四種邊框的不同的值,網頁制作者必須用一個或更多的屬性,如:上邊框、右邊框、下邊框、左邊框、邊框顏色、邊框寬度、邊框式樣、上邊框寬度、右邊框寬度、下邊框寬度或左邊框寬度。 13.寬度 語法: width: <值> 允許值: <長度> | <百分比> | auto 初始值: auto 適用于: 塊級和替換元素 向下兼容: 否 寬度屬性的初始值為“auto”,即為該元素的原有寬度(有就是元素自己的寬度)。百分比參考上級元素的寬度。不允許使用負的長度值。 14.高度 語法: height: <值> 允許值: <長度> | auto 初始值: auto 適用于: 塊級和替換元素 向下兼容: 否 高度屬性的初始值為“auto”,即為該元素的原有高度(有就是元素自己的高度,)。百分比參考上級元素的寬度。不允許使用負的長度值。 15.有關標簽 table:表格標簽,對整個表格樣式的定義要放在table中; css濾鏡 隨著網頁設計技術的發展,人們已經不滿足于原有的一些HTML標記,而是希望能夠為頁面添加一些多媒體屬性,例如濾鏡的和漸變的效果。CSS技術的飛快發展使這些需求成為了現實。從現在開始我要為大家介紹一個新的CSS擴展部分:CSS濾鏡屬性(Filter Properties)。使用這種技術可以把可視化的濾鏡和轉換效果添加到一個標準的HTML元素上,例如圖片、文本容器、以及其他一些對象。對于濾鏡和漸變效果,前者是基礎,因為后者就是濾鏡效果的不斷變化和演示更替。當濾鏡和漸變效果結合到一個基本的SCRIPT小程序中后,網頁設計者就可以擁有一個建立動態交互文檔的強大工具。也就是CSS FILTER+ SCRIPT, 這就說明想要建立動態的文檔還要一些SCRIPT (腳本語言)的基礎。 備注:可惜只有IE4.0以上支持,如果是別的瀏覽器,那就....... 元素 說明
IE4.0以上支持的濾鏡屬性表 濾鏡效果 描述 1、Alpha 濾鏡 語法:{FILTER:ALPHA(opacity=opacity,finishopacity=finishopacity,style=style,startx=startx, "Alpha"屬性是把一個目標元素與背景混合。設計者可以指定數值來控制混合的程度。這種“與背景混合”通俗地說就是一個元素的透明度。通過指定坐標,可以指定點、線、面的透明度。他們的參數含義分別如下: 效果如下: 2、Blur 濾鏡 語法:對于HTML:{ilter:blur(add=add,direction=direction,strength=strength)} 3、FlipH, FlipV 濾鏡 語法:{filter:filph} ,{filter:filpv} 分別是水平反轉和垂直反轉,具體如下: 4、Chroma 濾鏡 語法:{filter:chroma(color=color)} 滴水檐坊 5、DropShadow 濾鏡 語法:{filter:dropshadow(color=color,offx=ofx,offy=offy,positive=positive)} “DropShaow"顧名思義就是添加對象的陰影效果。其工作原理是建立一個偏移量,加上較深。"Color"代表投射陰影的顏色,"offx"和"offy"分別是X方向和Y方向陰影的餓偏移量。"Positive"參數是一個布爾值,如果為“TRUE(非0)”,那么就為任何的非透明像素建立可見的投影。如果為“FASLE(0)”,那么就為透明的像素部分建立透明效果 6、Glow 濾鏡 語法:{filter:glow(color=color,strength)} 7、Gray ,Invert,Xray 濾鏡 語法:{filter:gray} ,{filter:invert},{filter:xray} Gray濾鏡是把一張圖片變成灰度圖;Invert濾鏡是把對象的可視化屬性全部翻轉,包括色彩、飽和度、和亮度值;Xray濾鏡是讓對象反映出它的輪廓并把這些輪廓加亮,也就是所謂的“X”光片。 效果如下: 、Light 濾鏡 語法:Filter{light} 這個屬性模擬光源的投射效果。一旦為對象定義了“LIGHT"濾鏡屬性,那么就可以調用它的“方法(Method)"來設置或者改變屬性。“LIGHT"可用的方法有: AddAmbient 加入包圍的光源 9、Mask 濾鏡 語法:{filter:mask(color=color)} 使用"MASK"屬性可以為對象建立一個覆蓋于表面的膜,其效果就象戴者有色眼鏡看物體一樣。 10、Shadow 濾鏡 語法:{filter:shadow(color=color,direction=direction)} 利用“Shadow”屬性可以在指定的方向建立物體的投影,COLOR是投影色,DIRECTION是設置投影的方向。其中0度代表垂直向上,然后每45度為一個單位。它的默認值是向左的270度。 filter:shadow(color=red,direction=225) 11、Wave 濾鏡 語法:{filter:wave(add=add,freq=freq,lightstrength=strength,phase=phase,strength=strength)} “FREQ”是波紋的頻率,也就是指定在對象上一共需要產生多少個完整的波紋, “LIGHTSTRENGTH”參數可以對于波紋增強光影的效果,范圍0----100, “PHASE”參數用來設置正弦波的偏移量。 “STRENGTH”代表振幅大小。 |