Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
C#編程語(yǔ)言中,屬性(Properties)是一種特殊的類成員,它們提供了對(duì)字段(Fields)的靈活訪問(wèn)。通過(guò)屬性,我們可以控制對(duì)類內(nèi)部數(shù)據(jù)的訪問(wèn),并執(zhí)行一些額外的邏輯,如數(shù)據(jù)驗(yàn)證或轉(zhuǎn)換。C#中的屬性通常是通過(guò)get和set訪問(wèn)器來(lái)定義的,這兩個(gè)訪問(wèn)器分別用于讀取和寫入屬性的值。
一、屬性的基本概念
屬性在C#中是一種特殊的類成員,它們提供了對(duì)私有字段的公共訪問(wèn)。通過(guò)屬性,我們可以隱藏類的內(nèi)部狀態(tài),只暴露必要的接口給類的使用者。這樣,我們可以更好地控制對(duì)類內(nèi)部數(shù)據(jù)的訪問(wèn),確保數(shù)據(jù)的完整性和安全性。
二、get訪問(wèn)器
get訪問(wèn)器用于讀取屬性的值。當(dāng)我們?cè)诖a中引用一個(gè)屬性時(shí),實(shí)際上是在調(diào)用該屬性的get訪問(wèn)器。get訪問(wèn)器必須返回一個(gè)值,該值的類型必須與屬性的聲明類型相匹配。
下面是一個(gè)簡(jiǎn)單的示例,展示了一個(gè)帶有g(shù)et訪問(wèn)器的屬性:
public class Person
{
private string _name; // 私有字段
public string Name // 公共屬性
{
get // get訪問(wèn)器
{
return _name; // 返回私有字段的值
}
}
}
在上面的示例中,Name
屬性通過(guò)get訪問(wèn)器暴露了_name
字段的值。當(dāng)我們創(chuàng)建一個(gè)Person
對(duì)象并嘗試訪問(wèn)其Name
屬性時(shí),實(shí)際上是在調(diào)用Name
屬性的get訪問(wèn)器,并返回_name
字段的值。
三、set訪問(wèn)器
set訪問(wèn)器用于寫入屬性的值。當(dāng)我們?yōu)閷傩再x值時(shí),實(shí)際上是在調(diào)用該屬性的set訪問(wèn)器。set訪問(wèn)器通常接受一個(gè)與屬性類型相同的參數(shù),并將其賦值給內(nèi)部的私有字段。
下面是一個(gè)帶有g(shù)et和set訪問(wèn)器的屬性的示例:
public class Person
{
private string _name; // 私有字段
public string Name // 公共屬性
{
get // get訪問(wèn)器
{
return _name; // 返回私有字段的值
}
set // set訪問(wèn)器
{
_name=value; // 將傳入的值賦給私有字段
}
}
}
在上面的示例中,Name
屬性不僅可以通過(guò)get訪問(wèn)器讀取值,還可以通過(guò)set訪問(wèn)器寫入值。當(dāng)我們?yōu)?code style='color: rgb(250, 139, 115);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(27, 31, 35, 0.05);width: auto;height: auto;margin-left: 2px;margin-right: 2px;padding: 2px 4px;border-style: none;border-width: 3px;border-color: rgb(0, 0, 0) rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.4);border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;'>Name屬性賦值時(shí),實(shí)際上是在調(diào)用set訪問(wèn)器,并將傳入的值賦給_name
字段。在set訪問(wèn)器內(nèi)部,我們使用了一個(gè)特殊的value
關(guān)鍵字來(lái)表示傳入的值。
四、屬性的使用場(chǎng)景
屬性的使用場(chǎng)景非常廣泛,它們可以用于控制對(duì)類內(nèi)部數(shù)據(jù)的訪問(wèn)權(quán)限、執(zhí)行數(shù)據(jù)驗(yàn)證、轉(zhuǎn)換數(shù)據(jù)類型等。例如,我們可以在set訪問(wèn)器中添加一些邏輯來(lái)確保賦給屬性的值是有效的,或者在get訪問(wèn)器中返回計(jì)算后的值而不是直接返回字段的值。
此外,屬性還可以用于實(shí)現(xiàn)一些設(shè)計(jì)模式,如觀察者模式(Observer Pattern)或依賴注入(Dependency Injection)。通過(guò)屬性的靈活訪問(wèn)機(jī)制,我們可以更好地控制類的行為和狀態(tài)。
五、總結(jié)
C#中的get和set訪問(wèn)器是屬性訪問(wèn)機(jī)制的重要組成部分。它們?cè)试S我們靈活地控制對(duì)類內(nèi)部數(shù)據(jù)的訪問(wèn),并執(zhí)行額外的邏輯。通過(guò)合理使用get和set訪問(wèn)器,我們可以創(chuàng)建出更加健壯、安全和易于使用的類庫(kù)和應(yīng)用程序。掌握這一機(jī)制對(duì)于深入理解C#面向?qū)ο缶幊讨陵P(guān)重要。
impleDateFormat 是 Java提供的一個(gè)格式化和解析日期的工具類,日常開發(fā)中應(yīng)該經(jīng)常會(huì)用到,但是它是線程不安全的。
多線程公用一個(gè) SimpleDateFormat實(shí)例 對(duì)日期進(jìn)行解析或者格式化會(huì)導(dǎo)致程序出錯(cuò),本節(jié)就討論下它為何是線程不安全的,以及如何避免。
public class TestSimpleDateFormat {
//(1)創(chuàng)建單例實(shí)例
static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
//(2)創(chuàng)建多個(gè)線程,并啟動(dòng)
for (int i=0; i <10 ; ++i) {
Thread thread=new Thread(new Runnable() {
public void run() {
try {//(3)使用單例日期實(shí)例解析文本
System.out.println(sdf.parse("2017-12-13 15:17:27"));
} catch (ParseException e) {
e.printStackTrace();
}
}
});
thread.start();//(4)啟動(dòng)線程
}
}
代碼(1)創(chuàng)建了SimpleDateFormat的一個(gè)實(shí)例;
代碼(2)創(chuàng)建10個(gè)線程,每個(gè)線程都共用同一個(gè)sdf對(duì)象對(duì)文本日期進(jìn)行解析,多運(yùn)行幾次就會(huì)拋出java.lang.NumberFormatException異常,加大線程的個(gè)數(shù)有利于該問(wèn)題復(fù)現(xiàn)。
為了便于分析首先奉上SimpleDateFormat的類圖結(jié)構(gòu):
SimpleDateFormat 類結(jié)構(gòu)圖
下面從代碼層面看下parse方法做了什么事情:
#### parse() 方法
public Date parse(String text, ParsePosition pos)
{
//(1)解析日期字符串放入CalendarBuilder的實(shí)例calb中
.....
Date parsedDate;
try {//(2)使用calb中解析好的日期數(shù)據(jù)設(shè)置calendar
parsedDate=calb.establish(calendar).getTime();
...
}
catch (IllegalArgumentException e) {
...
return null;
}
return parsedDate;
}
## establish() 方法
Calendar establish(Calendar cal) {
...
//(3)重置日期對(duì)象cal的屬性值
cal.clear();
//(4) 使用calb中中屬性設(shè)置cal
...
//(5)返回設(shè)置好的cal對(duì)象
return cal;
}
public final void clear() {
for (int i=0; i < fields.length; ) {
stamp[i]=fields[i]=0; // UNSET==0
isSet[i++]=false;
}
areAllFieldsSet=areFieldsSet=false;
isTimeSet=false;
}
從上面步驟可知步驟(3)(4)(5)操作不是原子性操作。
當(dāng)多個(gè)線程調(diào)用parse方法時(shí)候比如線程A執(zhí)行了步驟(3)(4)也就是設(shè)置好了cal對(duì)象,在執(zhí)行步驟(5)前線程B執(zhí)行了步驟(3)清空了cal對(duì)象,由于多個(gè)線程使用的是一個(gè)cal對(duì)象,所以線程A執(zhí)行步驟(5)返回的就可能是被線程B清空后的對(duì)象,當(dāng)然也有可能線程B執(zhí)行了步驟(4)被線程B修改后的cal對(duì)象。從而導(dǎo)致程序錯(cuò)誤。
每次使用時(shí)候new一個(gè)SimpleDateFormat的實(shí)例,這樣可以保證每個(gè)實(shí)例使用自己的Calendar實(shí)例,但是每次使用都需要new一個(gè)對(duì)象,并且使用后由于沒(méi)有其它引用,就會(huì)需要被回收,開銷會(huì)很大。
究其原因是因?yàn)槎嗑€程下步驟(3)(4)(5)三個(gè)步驟不是一個(gè)原子性操作,那么容易想到的是對(duì)其進(jìn)行同步,讓(3)(4)(5)成為原子操作,可以使用synchronized進(jìn)行同步。
public class TestSimpleDateFormat {
// (1)創(chuàng)建單例實(shí)例
static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
// (2)創(chuàng)建多個(gè)線程,并啟動(dòng)
for (int i=0; i < 10; ++i) {
Thread thread=new Thread(new Runnable() {
public void run() {
try {// (3)使用單例日期實(shí)例解析文本
synchronized (sdf) {
System.out.println(sdf.parse("2017-12-13 15:17:27"));
}
} catch (ParseException e) {
e.printStackTrace();
}
}
});
thread.start();// (4)啟動(dòng)線程
}
}
}
使用同步意味著多個(gè)線程要競(jìng)爭(zhēng)鎖,在高并發(fā)場(chǎng)景下會(huì)導(dǎo)致系統(tǒng)響應(yīng)性能下降。
每個(gè)線程只需要使用一個(gè) SimpleDateFormat 實(shí)例相比第一種方式大大節(jié)省了對(duì)象的創(chuàng)建銷毀開銷,并且不需要對(duì)多個(gè)線程直接進(jìn)行同步。
public class TestSimpleDateFormat2 {
// (1)創(chuàng)建threadlocal實(shí)例
static ThreadLocal<DateFormat> safeSdf=new ThreadLocal<DateFormat>(){
@Override
protected SimpleDateFormat initialValue(){
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static void main(String[] args) {
// (2)創(chuàng)建多個(gè)線程,并啟動(dòng)
for (int i=0; i < 10; ++i) {
Thread thread=new Thread(new Runnable() {
public void run() {
try {// (3)使用單例日期實(shí)例解析文本
System.out.println(safeSdf.get().parse("2017-12-13 15:17:27"));
} catch (ParseException e) {
e.printStackTrace();
}
}
});
thread.start();// (4)啟動(dòng)線程
}
}
}
如果線程調(diào)用多個(gè)類的其他方法,并且其他地方需要日期格式化,在線程代碼中new的對(duì)象,其他地方不一定會(huì)訪問(wèn)得到。如果想復(fù)用的話,
【ThreadLocal 中設(shè)置的變量是線程本身變量池的值,所以只要是同一線程,在執(zhí)行任何類的代碼的時(shí)候都可以獲取得到;只需要?jiǎng)?chuàng)建一個(gè)實(shí)例】。
就像在使用pagehelper設(shè)置分頁(yè)參數(shù)時(shí),它就是放在ThreadLocal中的,所以后續(xù)的查詢調(diào)用其他類的其他方法,需要這幾個(gè)值都是直接從線程本身取這個(gè)值。
不過(guò)ThreadLocal使用完其中的值后最好remove下,不然一些情況會(huì)造成內(nèi)存泄露。
原文 https://cn-blogs.cn/archives/10783.html
這里分類和匯總了欣宸的全部原創(chuàng)(含配套源碼):https://github.com/zq2599/blog_demos
名稱 | 鏈接 | 備注 |
項(xiàng)目主頁(yè) | https://github.com/zq2599/blog_demos | 該項(xiàng)目在GitHub上的主頁(yè) |
git倉(cāng)庫(kù)地址(https) | https://github.com/zq2599/blog_demos.git | 該項(xiàng)目源碼的倉(cāng)庫(kù)地址,https協(xié)議 |
git倉(cāng)庫(kù)地址(ssh) | git@github.com:zq2599/blog_demos.git | 該項(xiàng)目源碼的倉(cāng)庫(kù)地址,ssh協(xié)議 |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
bind-service: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30000
kubectl apply -f deployment-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: other-deployment
spec:
selector:
matchLabels:
app: other
replicas: 1
template:
metadata:
labels:
app: other
bind-service: none
spec:
containers:
- name: other
image: nginx:latest
ports:
- containerPort: 80
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-544dc8b7c4-xlkj8 1/1 Running 0 2m20s
other-deployment-7659c57b9d-2slm8 1/1 Running 0 5s
tree client-go-tutorials
client-go-tutorials
├── action
│ ├── action.go
│ ├── conflict.go
│ ├── controller.go
│ ├── controller_demo.go
│ ├── label.go
│ └── list_pod.go
├── go.mod
├── go.sum
└── main.go
1 directory, 9 files
type Lable struct{}
// listPods 根據(jù)傳入的selector過(guò)濾
func listPods(clientset *kubernetes.Clientset, selector labels.Selector, prefix string) {
namespace :="default"
// 查詢pod列表
pods, err :=clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
// 傳入的selector在這里用到
LabelSelector: selector.String(),
})
if err !=nil {
panic(err.Error())
}
nums :=len(pods.Items)
log.Printf("[%v] 查到[%d]個(gè)pod\n", prefix, nums)
// 如果沒(méi)有pod就返回了
if nums < 1 {
return
}
// 遍歷列表中的每個(gè)pod
for index, pod :=range pods.Items {
log.Printf("[%v] %v. pod : %v\n", prefix, index+1, pod.Name)
}
}
func (lable Lable) DoAction(clientset *kubernetes.Clientset) error {
// 第一種: 創(chuàng)建Requirement對(duì)象,指定類型是Equals(等于)
equalRequirement, err :=labels.NewRequirement("app", selection.Equals, []string{"other"})
if err !=nil {
log.Println("1. create equalRequirement fail, ", err)
return err
}
selector :=labels.NewSelector().Add(*equalRequirement)
// 驗(yàn)證,應(yīng)該只查到app等于other的pod
listPods(clientset, selector, "用Requirement創(chuàng)建,Equal操作")
// 第一種: 創(chuàng)建Requirement對(duì)象,指定類型是In,not_exists不會(huì)有任何pod匹配到
inRequirement, err :=labels.NewRequirement("app", selection.In, []string{"other", "nginx", "not_exists"})
if err !=nil {
log.Println("2. create equalRequirement fail, ", err)
return err
}
selector=labels.NewSelector().Add(*inRequirement)
// 驗(yàn)證,應(yīng)該查到app=other的pod
listPods(clientset, selector, "用Requirement創(chuàng)建,In操作")
// 第二種:labels.Parse方法
parsedSelector, err :=labels.Parse("bind-service=none,app notin (not_exists)")
if err !=nil {
log.Println("3. create equalRequirement fail, ", err)
return err
}
// 驗(yàn)證,應(yīng)該查到app=other的pod
listPods(clientset, parsedSelector, "用Parse創(chuàng)建")
// 第三種:labels.SelectorFromSet方法
setSelector :=labels.SelectorFromSet(labels.Set(map[string]string{"app": "nginx"}))
// 驗(yàn)證,應(yīng)該查到app=nginx的pod
listPods(clientset, setSelector, "用SelectorFromSet創(chuàng)建")
// 第四種:metav1.LabelSelectorAsSelector方法
// 適用于當(dāng)前環(huán)境已有資源對(duì)象的場(chǎng)景,可以取出LabelSelector對(duì)象來(lái)轉(zhuǎn)換成labels.Selector
// 先創(chuàng)建一個(gè)LabelSelector
labelSelector :=&metav1.LabelSelector{
MatchLabels: map[string]string{"app": "other"},
}
// 將LabelSelector轉(zhuǎn)為labels.Selector
convertSelector, err :=metav1.LabelSelectorAsSelector(labelSelector)
if err !=nil {
log.Println("4. create equalRequirement fail, ", err)
return err
}
// 驗(yàn)證,應(yīng)該查到app=nginx的pod
listPods(clientset, convertSelector, "用LabelSelector轉(zhuǎn)換")
// labels.Selector的第五種用法:用labels.Selector匹配
// 準(zhǔn)備好一個(gè)selector
matchSelector :=labels.SelectorFromSet(labels.Set(map[string]string{"app": "nginx"}))
// 查詢pod列表
pods, err :=clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
if err !=nil {
panic(err.Error())
}
// 遍歷列表中的每個(gè)pod
for _, pod :=range pods.Items {
if matchSelector.Matches(labels.Set(pod.GetLabels())) {
log.Printf("app=nginx匹配成功[%s]\n", pod.Name)
} else {
log.Printf("app=nginx匹配失敗[%s]\n", pod.Name)
}
}
return nil
}
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"args": ["-action=label"]
}
]
}
2023/03/11 19:57:53 解析命令完畢,開始加載配置文件
2023/03/11 19:57:53 加載配置文件完畢,即將執(zhí)行業(yè)務(wù) [label]
2023/03/11 19:57:53 [用Requirement創(chuàng)建,Equal操作] 查到[1]個(gè)pod
2023/03/11 19:57:53 [用Requirement創(chuàng)建,Equal操作] 1. pod : other-deployment-7b57cc4f89-bdxj8
2023/03/11 19:57:53 [用Requirement創(chuàng)建,In操作] 查到[2]個(gè)pod
2023/03/11 19:57:53 [用Requirement創(chuàng)建,In操作] 1. pod : nginx-deployment-5659dc6c45-hsx7j
2023/03/11 19:57:53 [用Requirement創(chuàng)建,In操作] 2. pod : other-deployment-7b57cc4f89-bdxj8
2023/03/11 19:57:53 [用Parse創(chuàng)建] 查到[1]個(gè)pod
2023/03/11 19:57:53 [用Parse創(chuàng)建] 1. pod : other-deployment-7b57cc4f89-bdxj8
2023/03/11 19:57:53 [用SelectorFromSet創(chuàng)建] 查到[1]個(gè)pod
2023/03/11 19:57:53 [用SelectorFromSet創(chuàng)建] 1. pod : nginx-deployment-5659dc6c45-hsx7j
2023/03/11 19:57:53 [用LabelSelector轉(zhuǎn)換] 查到[1]個(gè)pod
2023/03/11 19:57:53 [用LabelSelector轉(zhuǎn)換] 1. pod : other-deployment-7b57cc4f89-bdxj8
2023/03/11 19:57:53 執(zhí)行完成
func (controllerDemo ControllerDemo) DoAction(clientset *kubernetes.Clientset) error {
setSelector :=labels.SelectorFromSet(labels.Set(map[string]string{"app": "nginx"}))
optionsModifer :=func(options *metav1.ListOptions) {
options.LabelSelector=setSelector.String()
}
podListWatcher :=cache.NewFilteredListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", metav1.NamespaceDefault, optionsModifer)
// 創(chuàng)建ListWatch對(duì)象,指定要監(jiān)控的資源類型是pod,namespace是default
// podListWatcher :=cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", v1.NamespaceDefault, fields.Everything())
// 創(chuàng)建工作隊(duì)列
queue :=workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
// 創(chuàng)建informer,并將返回的存儲(chǔ)對(duì)象保存在變量indexer中
indexer, informer :=cache.NewIndexerInformer(podListWatcher, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
// 響應(yīng)新增資源事件的方法,可以按照業(yè)務(wù)需求來(lái)定制,
// 這里的做法比較常見:寫入工作隊(duì)列
AddFunc: func(obj interface{}) {
key, err :=cache.MetaNamespaceKeyFunc(obj)
if err==nil {
queue.Add(key)
}
},
// 響應(yīng)修改資源事件的方法,可以按照業(yè)務(wù)需求來(lái)定制,
// 這里的做法比較常見:寫入工作隊(duì)列
UpdateFunc: func(old interface{}, new interface{}) {
key, err :=cache.MetaNamespaceKeyFunc(new)
if err==nil {
queue.Add(key)
}
},
// 響應(yīng)修改資源事件的方法,可以按照業(yè)務(wù)需求來(lái)定制,
// 這里的做法比較常見:寫入工作隊(duì)列,注意刪除的時(shí)候生成key的方法和新增修改不一樣
DeleteFunc: func(obj interface{}) {
// IndexerInformer uses a delta queue, therefore for deletes we have to use this
// key function.
key, err :=cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err==nil {
queue.Add(key)
}
},
}, cache.Indexers{})
// 創(chuàng)建Controller對(duì)象,將所需的三個(gè)變量對(duì)象傳入
controller :=NewController(queue, indexer, informer)
// Now let's start the controller
stop :=make(chan struct{})
defer close(stop)
// 在協(xié)程中啟動(dòng)controller
go controller.Run(1, stop)
// Wait forever
select {}
return nil
}
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。