Java基礎(chǔ)之線程鎖相關(guān)知識總結(jié)
一、 synchronized關(guān)鍵字
1.對象鎖
a.當(dāng)使用對象鎖的時候,注意要是相同的對象,并且當(dāng)有線程正在訪問對象鎖內(nèi)部的代碼的時候,其他線程無法訪問。(注意無法訪問的范圍)。
b.但是并不影響沒有使用對象鎖的部分的代碼的運行。
對象鎖分為兩類一個叫做synchronized代碼塊(圓括號內(nèi)是普通類的對象),另外一個是sybchronized修飾普通成員方法。它們二者其實可以通過this關(guān)鍵字進項轉(zhuǎn)化。
2.類鎖
a. 當(dāng)使用類鎖的時候,只要是同一個類的對象.當(dāng)有線程正在訪問類鎖內(nèi)部的代碼的時候,其他線程無法訪問。(注意無法訪問的范圍)
b. 但是并不影響沒有使用類鎖的部分的代碼的運
對象鎖分為兩類一個叫做synchronized代碼塊(圓括號內(nèi)是class對象),另外一個是sybchronized修飾靜態(tài)成員方法。它們二者其實可以通過class對象進項轉(zhuǎn)化。
注意: 類鎖和對象鎖之間沒有關(guān)系.
1、不使用線程鎖
如果沒有加synchronized關(guān)鍵字,會產(chǎn)生線程交錯運行
/**
* 該類寫了一個test方法,先不加synchronized關(guān)鍵字
*/
public class A {
void test() {
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
}
}
/**
* 該類繼承Thread,重寫run方法調(diào)用A中的test方法
*/
public class MyThread1 extends Thread{
A a;
public void run() {
a.test();
}
}
/**
* 該類繼承Thread,重寫run方法調(diào)用A中的test方法
*/
public class MyThread2 extends Thread{
A a;
public void run() {
a.test();
}
}
/**
* 測試程序
* /
public class Entrance {
public static void main(String[] args) {
/**
* 演示沒有鎖時會產(chǎn)生交錯現(xiàn)象
*/
A a = new A();
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.a = a;
t2.a = a;
t1.start();
t2.start();
}
}
產(chǎn)生如下運行結(jié)果:
線程:0
線程:1
線程:2
線程:3
線程:4
線程:0
線程:5
線程:6
線程:7
線程:8
線程:9
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
2、使用對象鎖
將A類中test方法代碼改成如下代碼,其他不變,運行測試類可以產(chǎn)生如下結(jié)果
/**
* 該類寫了一個test方法,使用對象鎖
* 分別在鎖前鎖后增加代碼,演示對沒有使用對象鎖的代碼不會產(chǎn)生任何影響
* 且如果對象鎖被鎖住,對象鎖后面的代碼是不會運行的
*/
public class A {
void test() {
System.out.println("線程開始");
synchronized(this) {
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
}
System.out.println("線程結(jié)束");
}
}
運行測試類會產(chǎn)生如下結(jié)果:(注意:”線程開始“不是在對象鎖中的內(nèi)容)
線程開始
線程:0
線程:1
線程開始
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程結(jié)束
線程:7
線程:8
線程:9
線程結(jié)束
使用synchronized直接修飾方法等價于synchronized(this)修飾方法內(nèi)的全部代碼
/**
* synchronized直接修飾方法等價于synchronized(this)修飾方法內(nèi)的全部代碼
* test和test1方法是等價的
*/
public class A {
synchronized void test() {
System.out.println("線程開始");
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
System.out.println("線程結(jié)束");
}
void test1() {
synchronized (this) {
System.out.println("線程開始");
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
System.out.println("線程結(jié)束");
}
}
}
其他代碼是一樣的,在MyThread1和MyThread2中無論調(diào)用test還是test1,結(jié)果是一樣的,如下:
線程開始
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
線程結(jié)束
線程開始
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
線程結(jié)束
對象鎖對不同的方法也是有用的(類鎖也是如此)
/**
* 類鎖對不同的方法也是有用的
*/
public class A {
// synchronized void test() {
// for(int i=0;i<10;i++) {
// System.out.println("方法test:"+i);
// }
// }
void test() {
synchronized(this) {
for(int i=0;i<10;i++) {
System.out.println("方法test:"+i);
}
}
}
// synchronized void test1() {
// for(int i=0;i<10;i++) {
// System.out.println("方法test1:"+i);
// }
// }
void test1() {
synchronized(this) {
for(int i=0;i<10;i++) {
System.out.println("方法test1:"+i);
}
}
}
}
MyThread1中調(diào)用test方法,MyThread2中調(diào)用test1方法,運行結(jié)果如下:
方法test:0
方法test:1
方法test:2
方法test:3
方法test:4
方法test:5
方法test:6
方法test:7
方法test:8
方法test:9
方法test1:0
方法test1:1
方法test1:2
方法test1:3
方法test1:4
方法test1:5
方法test1:6
方法test1:7
方法test1:8
方法test1:9
3、使用類鎖
演示當(dāng)A類中的test方法使用對象鎖時,不同對象調(diào)用test方法時對象鎖是起不到任何作用的
/**
* 該類寫了一個test方法,使用對象鎖演示不用對象調(diào)用test方法
*/
public class A {
void test() {
synchronized(this) {
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
}
}
}
MyThread1和MyThread2是一樣的,主要在測試程序的不同
測試程序:
public class Entrance {
public static void main(String[] args) {
/**
* 演示使用不同的對象調(diào)用test方法時,對象鎖會產(chǎn)生交錯現(xiàn)象
* 而使用類鎖則不會產(chǎn)生這種現(xiàn)象
*/
A a1 = new A();
A a2 = new A();
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.a = a1;
t2.a = a2;
t1.start();
t2.start();
}
}
運行結(jié)果:
線程:0
線程:1
線程:2
線程:3
線程:4
線程:0
線程:5
線程:6
線程:7
線程:8
線程:9
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
使用類鎖會改變這種情況,無論是那個對象,只要調(diào)用的是同一個方法就會產(chǎn)生鎖
/**
* 該類寫了一個test方法,使用對象鎖演示不用對象調(diào)用test方法
* 將類A中的this改為A.class,其他代碼都不變
*/
public class A {
void test() {
synchronized(A.class) {
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
}
}
}
運行結(jié)果:
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
對象鎖分為兩類一個叫做synchronized代碼塊(圓括號內(nèi)是普通類的對象),另外一個是sybchronized修飾普通成員方法。它們二者其實可以通過this關(guān)鍵字進項轉(zhuǎn)化。
/**
* 該類寫了一個test方法,使用對象鎖演示不用對象調(diào)用test方法
* 將類A中的this改為A.class,其他代碼都不變
*/
public class A {
void test() {
synchronized(A.class) {
for(int i=0;i<10;i++) {
System.out.println("線程:"+i);
}
}
}
}
運行結(jié)果:
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
線程:0
線程:1
線程:2
線程:3
線程:4
線程:5
線程:6
線程:7
線程:8
線程:9
類鎖這對象鎖之間是沒有任何關(guān)系,互不影響互不干涉
/**
* 該類寫了test方法使用對象鎖,寫了test1方法使用類鎖
*/
public class A {
synchronized void test() {
for(int i=0;i<10;i++) {
System.out.println("方法test:"+i);
}
}
synchronized static void test1() {
for(int i=0;i<10;i++) {
System.out.println("方法test1:"+i);
}
}
}
MyThread1調(diào)用test方法,使用對象鎖,MyThread2調(diào)用test1方法,使用類鎖
測試程序
public class Entrance {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
/*
使用同一個對象調(diào)用test和test1會產(chǎn)生交錯現(xiàn)象
使用不同對象調(diào)用test和test1也會產(chǎn)生交錯現(xiàn)象
*/
// t1.a = a1;
// t2.a = a1;
t1.a = a1;
t2.a = a2;
t1.start();
t2.start();
}
}
運行結(jié)果:
方法test:0
方法test:1
方法test1:0
方法test1:1
方法test1:2
方法test1:3
方法test1:4
方法test1:5
方法test1:6
方法test1:7
方法test1:8
方法test1:9
方法test:2
方法test:3
方法test:4
方法test:5
方法test:6
方法test:7
方法test:8
方法test:9
到此這篇關(guān)于Java基礎(chǔ)之線程鎖相關(guān)知識總結(jié)的文章就介紹到這了,更多相關(guān)Java線程鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中BeanUtils.copyProperties基本用法與小坑
本文主要介紹了Java中BeanUtils.copyProperties基本用法與小坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
MybatisPlus為何可以不用@MapperScan詳解
這篇文章主要給大家介紹了關(guān)于MybatisPlus為何可以不用@MapperScan的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MybatisPlus具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-04-04
詳解spring boot starter redis配置文件
spring-boot-starter-Redis主要是通過配置RedisConnectionFactory中的相關(guān)參數(shù)去實現(xiàn)連接redis service。下面通過本文給大家介紹在spring boot的配置文件中redis的基本配置,需要的的朋友參考下2017-07-07
SpringBoot返回文件使前端下載的幾種方式小結(jié)
本文主要介紹了Spring Boot中幾種文件下載的方法,通過后端應(yīng)用下載文件并進行業(yè)務(wù)處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11

