java同步

同步代码块

解决线程安全问题的一种方案:使用同步代码块

​ 格式:synchronized(锁对象){

可能会出现线程安全问题的代码(访问共享数据的代码)}

​ 注意:

​ 1.通过代码块中的锁对象,可以使用任意的对象

​ 2.但是必须保证多个线程使用的锁对象是同一个

​ 3.锁对象作用:

​ 把同步代码块锁住,只让一个线程在同步代码块中执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class TestDesp implements Runnable{
private int r = 100;
Object object = new Object();
@Override
//设置线程任务

public void run(){
//使用死循环,让卖票操作重复执行
while(true){
synchronized (object){
//先判断票是否存在
if(r>0){
//提高安全问题出现问题的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出了多少票"+r);
r--;
}

}
}
}

public static void main(String[] args) {
//创建Runnable接口对象的实现类对象(lamada表达式方式)
Runnable runnable = () -> {
for (int i = 0; i < 100; i++) {
System.out.println("hello word");
}
};
//创建Runnable接口对象的实现类对象
TestDesp ts =new TestDesp();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread tss = new Thread(ts);
Thread tss1 = new Thread(runnable);
Thread tss2 = new Thread(ts);
//调用start方法开启多线程
tss.start();
tss1.start();
tss2.start();
}
}

image-20210915193024885

image-20210915193234304

同步方法

​ 使用synchronized修饰的方法就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

​ 格式:

1
2
3
public synchronized void method(){
可能会出现线程安全的代码
}

使用步骤:

​ 1.把访问了共享数据的代码抽取出来,放到一个方法中

​ 2.在方法上添加synchronized修饰符;

​ 格式:定义方法的格式

​ 修饰符 synchronized 返回值类型 方法名(参数列表){

​ 可能会出现线程安全的代码

​ }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package Day002;
import java.lang.*;

public class TestDesp implements Runnable{
private int r = 100;
Object object = new Object();
@Override
//设置线程任务
public void run(){
//使用死循环,让卖票操作重复执行
while(true){
plytak();
}
}
}
/*
定义一个同步方法
同步方法也会把方法内部的代码锁住
只让一个线程执行
同步方法的锁对象是谁?
就是实现类对象new TestDesp()
也就是this

*/
public synchronized void plytak (){
//先判断票是否存在
if(r>0){
//提高安全问题出现问题的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出了多少票"+r);
r--;
}

}
}


public static void main(String[] args) {
//创建Runnable接口对象的实现类对象(lamada表达式方式)
Runnable runnable = () -> {
for (int i = 0; i < 100; i++) {
System.out.println("hello word");
}
};
//创建Runnable接口对象的实现类对象
TestDesp ts =new TestDesp();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread tss = new Thread(ts);
Thread tss1 = new Thread(runnable);
Thread tss2 = new Thread(ts);
//调用start方法开启多线程
tss.start();
tss1.start();
tss2.start();
}
}

静态同步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package Day002;
import java.lang.*;

public class TestDesp implements Runnable{
private static int r = 100;
Object object = new Object();
@Override
//设置线程任务
public void run(){
//使用死循环,让卖票操作重复执行
while(true){
plytak();
}
}
}
/*

静态同步方法的
锁对象是谁?
不是this
this是创建对象后才产生的,静态方法优先于对象。
就是本类的class属性---class文件对象(反射)
也就是this

*/
public static synchronized void plytak (){
//先判断票是否存在
if(r>0){
//提高安全问题出现问题的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出了多少票"+r);
r--;
}

}
}


public static void main(String[] args) {
//创建Runnable接口对象的实现类对象(lamada表达式方式)
Runnable runnable = () -> {
for (int i = 0; i < 100; i++) {
System.out.println("hello word");
}
};
//创建Runnable接口对象的实现类对象
TestDesp ts =new TestDesp();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread tss = new Thread(ts);
Thread tss1 = new Thread(runnable);
Thread tss2 = new Thread(ts);
//调用start方法开启多线程
tss.start();
tss1.start();
tss2.start();
}
}

lock锁

解决线程安全问题的第三种方案:使用lock锁

java.util.concurrent.locks.lock锁

Lock 实现提供了比使用synchronized 方法和语句可获得更广泛的锁定操作。

Lock 接口中的方法:

void Lock() 获取锁

void unLock()释放锁

使用步骤:

1.在成员位置创建一个ReentrantLock对象

2.在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取

package Day002;
import java.lang.*;

public class TestDesp implements Runnable{
private static int r = 100;
Object object = new Object();
@Override
//设置线程任务
public void run(){
//使用死循环,让卖票操作重复执行
while(true){
plytak();
}
}
}
/*

静态同步方法的
锁对象是谁?
不是this
this是创建对象后才产生的,静态方法优先于对象。
就是本类的class属性---class文件对象(反射)
也就是this 

*/
public static synchronized void plytak (){
    //先判断票是否存在
           if(r>0){
               //提高安全问题出现问题的概率,让程序睡眠
               try {
                   Thread.sleep(10);
                   System.out.println(Thread.currentThread().getName()+"卖出了多少票"+r);
               r--;
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }finally{
               lock.unlock();
               }
               
       }

     }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
//创建Runnable接口对象的实现类对象(lamada表达式方式)
Runnable runnable = () -> {
for (int i = 0; i < 100; i++) {
System.out.println("hello word");
}
};
//创建Runnable接口对象的实现类对象
TestDesp ts =new TestDesp();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread tss = new Thread(ts);
Thread tss1 = new Thread(runnable);
Thread tss2 = new Thread(ts);
//调用start方法开启多线程
tss.start();
tss1.start();
tss2.start();
}

线程状态

等待唤醒

​ 线程之间的通信

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class DemowaitAndNotify(){
/*
创建一个顾客线程(消费者):告知老板要的包子种类喝数量,调用wait方法,放弃cpu的执行,进入都WAITING状态(无线等待)
创建一个拉板线程(生产者):花了五秒做好包子之后,调用notify方法,唤醒顾客吃包子。
注意:
顾客喝老板线程必须使用同步代码块包裹起来,保证等待喝唤醒只能有一个在执行,同步使用的锁对象必须保证唯一,只有锁对象才能调用wait喝notify方法
Obejct类中的方法
void wait()
在其他线程调用此对象的notify()方法或notifyAll()方法之前,导致当前线程等待。
void notify()
唤醒在此对象监视器上等待的单个线程。
会继续执行wait方法之后的代码

*/

public static void main(String {} args){
//创建锁对象,保证唯一
Object obj = new Object();
@Override
//创建顾客线程,(消费者)
public void run() {
synchronized (obj) {
System.out.println("老板我要买包子一百个");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("包子好了开始吃包子");
}
}.start();

new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
obj.notify();
System.out.println("老板五秒钟做好了包子。把包子给顾客");

}
}
}.start();

}
}

wait带参方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package Day002;

public class Demowiat {
public static void main(String[] args) {
//创建锁对象保证唯一
Object obj = new Object();
new Thread() {
@Override
//创建顾客线程,(消费者)
public void run() {
while (true){
synchronized (obj) {
System.out.println("顾客一 老板我要买包子2百个");
try {
obj.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("包子好了开始吃包子"+'\n'+"===================================");
}}
}.start();
}}


notifyAll方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package Day002;

public class Demowiat {
public static void main(String[] args) {
//创建锁对象保证唯一
Object obj = new Object();
new Thread() {
@Override
//创建顾客线程,(消费者)
public void run() {
while (true){
synchronized (obj) {
System.out.println("顾客一 老板我要买包子2百个");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("包子好了开始吃包子"+'\n'+"===================================");
}}
}.start();
new Thread() {
@Override
//创建顾客线程,(消费者)
public void run() {
while (true){
synchronized (obj) {
System.out.println("顾客二 老板我要买包子一百个");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("包子好了开始吃包子"+'\n'+"===================================");
}}
}.start();


new Thread() {
public void run() {
while (true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}

synchronized (obj) {
obj.notifyAll();
System.out.println("老板五秒钟做好了包子。把包子给顾客");

}
}}
}.start();

}
}

版权声明: 本网站所有文章除特别声明外,著作权归作者所有。转载请注明出处!

-------- 本文结束 感谢阅读 --------