线程的同步问题
多线程带来的问题:
线程有时候回和其他线程共享一些资源,比如内存、数据库等。当多个线程同时读写同一份共享资源的时候,可能会发生冲突。这时候,我们就需要引入线程“同步”机制,即各位线程之间要有顺序使用,不能杂乱无章随意使用。
实例:
线程A
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private String context;
public ThreadA(String context) {
super();
this.context = context;
}
@Override
public void run() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
}
System.out.println();
}
}
线程B
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private String context;
public ThreadB(String context) {
super();
this.context = context;
}
@Override
public void run() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
}
System.out.println();
}
}
主线程
package threadTest.test7;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
new Thread(new ThreadA("12345678910")).start();
new Thread(new ThreadB("abcdefghijk")).start();
}
}
如果一般情况下分析结果应该为:
12345678910
abcdefghijk
但是某种情况下却出现:
也就是有些情况下线程A的for循环还未执行完,cpu就把资源给了线程B,结果就造成这样的问题
解决办法:
1.同步代码块:
要用同步代码块的话需要一个锁,而且两个线程必须用同一个锁,我们对上面的代码进行改进:
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private String context;
private Object obj;//充当锁,并不具有业务意义
public ThreadA(String context,Object obj) {
super();
this.obj=obj;
this.context = context;
}
@Override
public void run() {
synchronized(obj) {//锁住obj
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println();
}
}
package threadTest.test7;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private String context;
private Object obj;//充当锁,并不具有业务意义
public ThreadB(String context,Object obj) {
super();
this.obj=obj;
this.context = context;
}
@Override
public void run() {
synchronized(obj) {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println();
}
}
package threadTest.test7;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Object obj=new Object();
new Thread(new ThreadA("12345678910",obj)).start();
new Thread(new ThreadB("abcdefghijk",obj)).start();
}
}
为了cpu实现明显的切换效果,在每次循环中都加了Thread.sleep(1);,睡眠一毫秒
这样就能保证synchronized代码块中的代码能够执行完,而不会出现错误
2.同步方法:
synchronized 修饰方法,即锁定当前要执行的方法的对象
代码:
package threadTest.test8;
public class Node {
private String context;
public Node(String context) {
super();
this.context = context;
}
public void p() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
}
}
package threadTest.test8;
/**
* @author LENOVO
*/
public class ThreadA implements Runnable{
private Node n;
public ThreadA(Node n) {
super();
this.n=n;
}
@Override
public void run() {
n.p();
}
}
package threadTest.test8;
/**
* @author LENOVO
*/
public class ThreadB implements Runnable{
private Node n;
public ThreadB(Node n) {
super();
this.n=n;
}
@Override
public void run() {
n.p();
}
}
package threadTest.test8;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Node n=new Node("123456789");
new Thread(new ThreadA(n)).start();
new Thread(new ThreadB(n)).start();
}
}
执行结果:
发现没有达到目的
那么在Node类的p方法中加 synchronized 关键字如:
public synchronized void p() {
for(int i=0;i<context.length();i++) {
System.out.print(context.charAt(i));
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println();
}
再次执行
达到了我们想要的目的
如果主线程改成:
package threadTest.test8;
/**
* 主线程
* @author LENOVO
*/
public class Test1 {
public static void main(String[] args) {
Node n=new Node("123456789");
Node n2=new Node("abcdefghijk");
new Thread(new ThreadA(n)).start();
new Thread(new ThreadB(n2)).start();
}
}
发现结果为
原因就是因为 同步方法锁定的是当前要执行的方法的对象,但是n和n2不是同一个对象,所以并没有达到效果
总结:
评论区
请写下您的评论...
猜你喜欢
blog
线程之间的通讯
java基础
3301
1.什么是线程通信线程之间通信的两个基本问题是互斥和同步。线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒
ofc
进程同步、进程互斥
official
1010
,因此“写数据”和“读数据”两个操作执行的先后顺序是不确定的。而实际应用中,又必须按照“写数据→读数据”的顺序来执行的。如何解决这种异步问题,就是“进程同步”所讨论的内容。同步亦称直接制约关系,它是指为
java基础
2078
一、什么是countDownlatchCountDownLatch是一个同步工具类,它通过一个计数器来实现的,初始值为线程的数量。每当一个线程完成了自己的任务,计数器的值就相应得减1。当计数器到达0
ofc
进程和线程的区别
weblog
1295
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。包含关系:一个进程内可以有多个线程(默认有一个主线程),线程是进程的一部分,必须依赖于进程而存在,不能独立存在。资源共享:进程之间是不共享资源的,多个线程之间是共享资源的,所以存在资源竞争的问题。
ofc
线程的五种基本状态
official
1110
线程的五种基本状态:初始化、可运行、运行、阻塞、终止阻塞状态分为:等待阻塞、同步阻塞、其他阻塞三种方式等待阻塞:调用某锁对象的wait方法可使当前线程进入等待阻塞状态,并且该线程放弃所有资源(包括
blog
线程的状态
java基础
3352
”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。3.运行状态(Running):线程获取C
official
1285
在上一节《一起学netty(6)》的文章中,简要说明了用nio原生代码写程序的一些不足和问题,以及netty在nio的基础上大致做了那些工作。其中提到一点就是当活跃客户端的数量太多,单线程处理时所带
blog
八皇后问题
数据结构与算法
7824
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行
最新发表
归档
2018-11
12
2018-12
33
2019-01
28
2019-02
28
2019-03
32
2019-04
27
2019-05
33
2019-06
6
2019-07
12
2019-08
12
2019-09
21
2019-10
8
2019-11
15
2019-12
25
2020-01
9
2020-02
5
2020-03
16
2020-04
4
2020-06
1
2020-07
7
2020-08
13
2020-09
9
2020-10
5
2020-12
3
2021-01
1
2021-02
5
2021-03
7
2021-04
4
2021-05
4
2021-06
1
2021-07
7
2021-08
2
2021-09
8
2021-10
9
2021-11
16
2021-12
14
2022-01
7
2022-05
1
2022-08
3
2022-09
2
2022-10
2
2022-12
5
2023-01
3
2023-02
1
2023-03
4
2023-04
2
2023-06
3
2023-07
4
2023-08
1
2023-10
1
2024-02
1
2024-03
1
2024-04
1
2024-08
1
标签
算法基础
linux
前端
c++
数据结构
框架
数据库
计算机基础
储备知识
java基础
ASM
其他
深入理解java虚拟机
nginx
git
消息中间件
搜索
maven
redis
docker
dubbo
vue
导入导出
软件使用
idea插件
协议
无聊的知识
jenkins
springboot
mqtt协议
keepalived
minio
mysql
ensp
网络基础
xxl-job
rabbitmq
haproxy
srs
音视频
webrtc
javascript
加密算法
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。