Pernyataan SyncLock
Memperoleh kunci eksklusif untuk blok pernyataan sebelum mengeksekusi blok.
Sintaks
SyncLock lockobject
[ block ]
End SyncLock
Generator
lockobject
Harus diisi. Ekspresi yang mengevaluasi ke referensi objek.
block
Opsional. Blok pernyataan yang akan dieksekusi ketika kunci diperoleh.
End SyncLock
Mengakhiri SyncLock
blok.
Keterangan
Pernyataan SyncLock
memastikan bahwa beberapa utas tidak mengeksekusi blok pernyataan pada saat yang bersamaan. SyncLock
mencegah setiap utas memasuki blok sampai tidak ada utas lain yang menjalankannya.
Penggunaan paling umum dari SyncLock
adalah untuk melindungi data agar tidak diperbarui oleh lebih dari satu utas secara bersamaan. Jika pernyataan yang memanipulasi data harus diselesaikan tanpa gangguan, masukkan ke dalam blok SyncLock
.
Blok pernyataan yang dilindungi oleh kunci eksklusif terkadang disebut bagian kritis .
Aturan
Percabangan. Anda tidak dapat bercabang menjadi
SyncLock
blok dari luar blok.Kunci Nilai Objek. Nilai
lockobject
tidak bolehNothing
. Anda harus membuat objek kunci sebelum menggunakannya dalam pernyataanSyncLock
.Anda tidak dapat mengubah nilai
lockobject
saat menjalankan blokSyncLock
. Mekanismenya mengharuskan objek kunci tetap tidak berubah.Anda tidak dapat menggunakan operator Menunggu di blok
SyncLock
.
Perilaku
Mekanisme. Saat utas mencapai pernyataan
SyncLock
, utas mengevaluasi ekspresilockobject
dan menangguhkan eksekusi hingga memperoleh kunci eksklusif pada objek yang dikembalikan oleh ekspresi. Ketika utas lain mencapai pernyataanSyncLock
, itu tidak memperoleh kunci sampai utas pertama mengeksekusi pernyataanEnd SyncLock
.Data yang Dilindungi. Jika
lockobject
adalah variabelShared
, kunci eksklusif mencegah utas dalam setiap instance kelas dari mengeksekusi blokSyncLock
saat utas lain menjalankannya. Ini melindungi data yang dibagikan di antara semua instance.Jika
lockobject
adalah variabel instans (bukanShared
), kunci mencegah utas yang berjalan di instans saat ini mengeksekusi blokSyncLock
pada saat yang sama dengan utas lain dalam instans yang sama. Ini melindungi data yang dikelola oleh instance individu.Akuisisi dan Pelepasan. Blok
SyncLock
berperilaku seperti konstruksiTry...Finally
di mana blokTry
memperoleh kunci eksklusif padalockobject
dan blokFinally
melepaskannya. Karena itu,SyncLock
blok menjamin pelepasan kunci, tidak peduli bagaimana Anda keluar dari blok. Ini benar bahkan dalam kasus pengecualian yang tidak ditangani.Panggilan Kerangka.
SyncLock
memperoleh dan melepaskan kunci eksklusif dengan memanggil metodeEnter
danExit
dari kelasMonitor
di ruang nama System.Threading.
Praktek Pemrograman
lockobject
harus selalu mengevaluasi ke objek yang dimiliki secara eksklusif oleh kelas Anda. Anda harus mendeklarasikan variabel objek Private
untuk melindungi data milik instance saat ini, atau variabel objek Private Shared
untuk melindungi data yang umum untuk semua instance.
Anda tidak boleh menggunakan kata kunci Me
untuk menyediakan objek kunci sebagai contoh data. Jika kode di luar kelas Anda memiliki referensi ke instance kelas Anda, kode tersebut dapat menggunakan referensi itu sebagai objek kunci untuk blok SyncLock
yang sama sekali berbeda dari milik Anda, melindungi data yang berbeda. Dengan cara ini, kelas Anda dan kelas lain dapat saling memblokir agar tidak mengeksekusi blok SyncLock
yang tidak terkait. Demikian pula penguncian pada string dapat menjadi masalah karena kode lain dalam proses yang menggunakan string yang sama akan berbagi kunci yang sama.
Anda juga tidak boleh menggunakan metode Me.GetType
untuk menyediakan objek kunci untuk data bersama. Ini karena GetType
selalu mengembalikan objek Type
yang sama untuk nama kelas yang diberikan. Kode eksternal dapat memanggil GetType
di kelas Anda dan mendapatkan objek kunci yang sama dengan yang Anda gunakan. Ini akan mengakibatkan dua kelas saling memblokir dari SyncLock
blok mereka.
Contoh
Deskripsi
Contoh berikut menunjukkan kelas yang memelihara daftar pesan sederhana. Ini menyimpan pesan dalam array dan elemen yang terakhir digunakan dari array itu dalam sebuah variabel. Prosedur addAnotherMessage
menambah elemen terakhir dan menyimpan pesan baru. Kedua operasi tersebut dilindungi oleh pernyataan SyncLock
dan End SyncLock
, karena setelah elemen terakhir ditambahkan, pesan baru harus disimpan sebelum utas lain dapat menambahkan elemen terakhir lagi.
Jika kelas simpleMessageList
berbagi satu daftar pesan di antara semua instance-nya, variabel messagesList
dan messagesLast
akan dideklarasikan sebagai Shared
. Dalam hal ini, variabel messagesLock
juga harus Shared
, sehingga akan ada satu objek kunci yang digunakan oleh setiap instance.
Kode
Class simpleMessageList
Public messagesList() As String = New String(50) {}
Public messagesLast As Integer = -1
Private messagesLock As New Object
Public Sub addAnotherMessage(ByVal newMessage As String)
SyncLock messagesLock
messagesLast += 1
If messagesLast < messagesList.Length Then
messagesList(messagesLast) = newMessage
End If
End SyncLock
End Sub
End Class
Deskripsi
Contoh berikut menggunakan utas dan SyncLock
. Selama pernyataan SyncLock
ada, blok pernyataan adalah bagian kritis dan balance
tidak pernah menjadi bilangan negatif. Anda dapat mengomentari pernyataan SyncLock
dan End SyncLock
untuk melihat efek dari mengabaikan kata kunci SyncLock
.
Kode
Imports System.Threading
Module Module1
Class Account
Dim thisLock As New Object
Dim balance As Integer
Dim r As New Random()
Public Sub New(ByVal initial As Integer)
balance = initial
End Sub
Public Function Withdraw(ByVal amount As Integer) As Integer
' This condition will never be true unless the SyncLock statement
' is commented out:
If balance < 0 Then
Throw New Exception("Negative Balance")
End If
' Comment out the SyncLock and End SyncLock lines to see
' the effect of leaving out the SyncLock keyword.
SyncLock thisLock
If balance >= amount Then
Console.WriteLine("Balance before Withdrawal : " & balance)
Console.WriteLine("Amount to Withdraw : -" & amount)
balance = balance - amount
Console.WriteLine("Balance after Withdrawal : " & balance)
Return amount
Else
' Transaction rejected.
Return 0
End If
End SyncLock
End Function
Public Sub DoTransactions()
For i As Integer = 0 To 99
Withdraw(r.Next(1, 100))
Next
End Sub
End Class
Sub Main()
Dim threads(10) As Thread
Dim acc As New Account(1000)
For i As Integer = 0 To 9
Dim t As New Thread(New ThreadStart(AddressOf acc.DoTransactions))
threads(i) = t
Next
For i As Integer = 0 To 9
threads(i).Start()
Next
End Sub
End Module