java线程同步操作实例详解
作者:shuair 发布时间:2023-11-13 14:19:08
本文实例讲述了java线程同步操作。分享给大家供大家参考,具体如下:
java线程同步
public class Hello {
public static void main(String[] args) {
MyRun myRun0 = new MyRun();
new Thread(myRun0, "Thread0").start();
new Thread(myRun0, "Thread1").start();
new Thread(myRun0, "Thread2").start();
}
}
class MyRun implements Runnable {
private int k = 0;
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "**********" + i);
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
}
}
输出结果
Thread0**********0
Thread1**********0
Thread2**********0
Thread1,2
Thread2,3
Thread1**********1
Thread2**********1
Thread2**********2
Thread1**********2
Thread0,7
Thread0**********1
Thread0**********2
说明多线程在某些场景是存在问题的,有时候需要线程同步。
同步 synchronized
同步代码块,synchronized(obj){}
,obj是一个对象,在这里就相当于一把锁,表示一旦有进程抢到了这把锁的钥匙(就是进入了代码块),其他进程将无法进入该锁的代码块(当前代码块其他进程一定是进不来了,其他地方的代码块如果也是用了这把锁,同样进不去),只有代码块执行完,释放锁后,所有进程再重新抢钥匙。
注意,上同一把锁的代码块都会被锁住,这些代码块可能写在不同方法不同位置上。
被同步代码块包住的代码多个线程只能顺次进入。
synchronized (this) {
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
this
表示当前对象,这里考虑的只是运行这个方法,不涉及其它类也不涉及这个类的其它地方需要同步问题,所以用this
也是可以的。k增加和输出一个流程内只能有一个线程在访问,所以可以得到想要的输出结果
输出结果
Thread0**********0
Thread1**********0
Thread2**********0
Thread0,1
Thread0**********1
Thread2,2
Thread2**********1
Thread1,3
Thread1**********1
Thread0**********2
Thread2**********2
Thread1**********2
对方法进行同步,如果存在多线程,每个线程顺次访问该方法
注意,如果一个类里面存在多个同步方法,那么这些同步方法的锁是一个,都是当前对象,所以不同线程想同时访问同一对象的不同方法也是不行的,因为这些方法都上了同一把锁,但是钥匙只有一把,只能一个线程持有。
@Override
public synchronized void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "**********" + i);
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
}
输出结果
Thread0**********0
Thread0,1
Thread0**********1
Thread0,2
Thread0**********2
Thread0,3
Thread2**********0
Thread2**********1
Thread2**********2
Thread1**********0
Thread1**********1
Thread1**********2
死锁
public class Hello {
public static void main(String[] args) {
A a = new A();
B b = new B();
new Thread(new MyRun(a,b)).start();
new Thread(new MyRun1(a,b)).start();
}
}
class MyRun implements Runnable{
private A a;
private B b;
public MyRun(A a, B b) {
this.a = a;
this.b = b;
}
@Override
public void run(){
a.say(b);
}
}
class MyRun1 implements Runnable {
private A a;
private B b;
public MyRun1(A a, B b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
b.say(a);
}
}
class A{
public synchronized void say(B b){
System.out.println("A要知道B的信息");
b.info();
}
public synchronized void info(){
System.out.println("这是A");
}
}
class B{
public synchronized void say(A a){
System.out.println("B要知道A的信息");
a.info();
}
public synchronized void info(){
System.out.println("这是B");
}
}
如果两个线程同时进入了两个say方法,就是出现死锁。
关键点在于一个对象的多个同步方法具有相同的锁,都是当前对象。也就是x线程在访问a对象的say方法过程中,y线程是无法访问a对象的info方法的,因为开锁的钥匙已经被x线程抢占了。
上面的程序,如果线程x,y同时进入了两个say方法,a对象同步方法的锁被线程x抢占,b对象同步方法的锁被线程y抢占,此时线程x无法访问b对象的同步方法,线程y无法访问a对象的同步方法。代码中恰好想要访问,所以就出现死锁了。
更多java相关内容感兴趣的读者可查看本站专题:《Java进程与线程操作技巧总结》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》
希望本文所述对大家java程序设计有所帮助。
来源:https://blog.csdn.net/shuair/article/details/81906040
猜你喜欢
- Swagger是一款遵循 Restful 风格的接口文档开发神器,支持基于 API 自动生成接口文档,接口文档始终与 API 保持同步,不再
- java 根据经纬度获取地址实现代码实现代码:public class GetLocation { public
- 一、实现流程1.注册2.登录3.登录保持【状态续签】二、实现方法项目结构1.引入依赖<!-- spring-web --><
- 里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改
- 本文简要介绍如何使用Spring Cloud Gateway 作为API 网关(不是使用zuul作为网关),关于Spring Cloud G
- 最近在开发项目的时候遇到一个问题,在myecilpes上使用googlede gson读取项目中的json文件成功,然后把项目发布到tomc
- startActivityForResult与startActivity的不同之处在于:1、startActivity( )仅仅是跳转到目标
- 自定义starterSpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进 starter,应用
- Java类加载器1、BootClassLoader: 用于加载Android Framework层class文件。2、PathClassLo
- 1.概述在本教程中,我们将讨论如何使用Spring Security OAuth和Spring Boot实现SSO - 单点登录。我们将使用
- 网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具。接下来就介绍一下爬虫的简单实现。爬虫的工作流程如下爬虫自指定的URL地址开
- 不管eclipse有没有被被时代抛弃,反正是被我抛弃了,因为IDEA是真的好用现在公司的项目基本都是基于maven的多module项目,co
- 接收JSON浏览器传来的参数,可以是 key/value 形式的,也可以是一个 JSON 字符串。在 Jsp/Servlet 中,我们接收
- 本文提纲版本约定JDK:8Servlet:4.xtomcat:9.x✍正文什么样的答案终身难忘?学生时代关于记忆经常能听见两种论调:死记硬背
- OutputDebugString属于windows API的,所以只要是包含了window.h这个头文件后就可以使用了。可以把调
- state:比较常用,各种状态都可以用它,但是它更着重于一种心理状态或者物理状态。Status:用在人的身上一般是其身份和地位,作“状态,情
- 本实例实现在jsp页面实现查询全国城市天气预报的功能,供大家参考,具体内容如下实例目录:实现效果:具体思路:从和风天气api那里取得具体城市
- 基础知识介绍: @RequestBody主要用来接收前端传递给后端的json字符串中的
- Java Map.values()方法获取Map集合中的所有键值对象Java 集合类中的 Map.values() 方法用来获取
- 主要技术实现:spring、 springmvc、 redis、 springboot、 mybatis 、sessi