Java SE入门及基础(60) 线程的实现(下) 线程的同步(synchronized 和 Lock 的实现) 线程通信 线程状态

news2025/1/19 8:22:42

目录

线程 (下)

4. 线程同步-synchronized

同步方法语法

示例

同步代码块语法

示例

synchronized锁实现原理

5. 线程同步-Lock

示例

6. 线程通信

Object类中的通信方法

案例

分析

代码实现

7. 线程状态

线程状态转换图


线程 (下)

4. 线程同步-synchronized

        The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements
        Java编程语言提供了两种基本的同步习惯用法:同步方法和同步代码块
同步方法语法
访问修饰符 synchronized 返回值类型 方法名 ( 参数列表 ){
}
示例
public class SaleThreadTest {
        public static void main ( String [] args ) {
                SaleTask task = new SaleTask (); // 一个成员
                Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员
                Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员
                Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员
                t1 . start ();
                t2 . start ();
                t3 . start ();
        }
        static class SaleTask implements Runnable {
                private int totalTickets = 10 ; // 售卖 10 张火车票
                //synchronized作用在成员方法上,因此synchronized 与成员有关
                private synchronized void saleTicket (){
                        if ( totalTickets > 0 ){
                                String name = Thread . currentThread (). getName ();
                                System . out . println ( name + " 售卖火车票: " + totalTickets );
                                totalTickets -- ;
                        }
                }
                @Override
                public void run () {
                        while ( true ){
                                saleTicket ();
                                if ( totalTickets == 0 ) break ;
                                try {
                                     Thread . sleep ( 100L );
                                } catch ( InterruptedException e ) {
                                      e . printStackTrace ();
                                }
                        }
                }
        }
}
同步代码块语法
synchronized ( 对象 ){
}
示例
public class SaleThreadTest {
        public static void main ( String [] args ) {
                SaleTask task = new SaleTask (); // 一个成员
                Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员
                Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员
                Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员
                t1 . start ();
                t2 . start ();
                t3 . start ();
        }
        static class SaleTask implements Runnable {
                private int totalTickets = 10 ; // 售卖 10 张火车票
                private Object o = new Object ();
                //synchronized作用在成员方法上,因此synchronized 与成员有关
                // private synchronized void saleTicket(){
                // if(totalTickets > 0){
                        // String name = Thread.currentThread().getName();
                        // System.out.println(name + "售卖火车票:" + totalTickets);
                        // totalTickets --;
                // }
        // }
        @Override
        public void run () {
                while ( true ){
                        // saleTicket();
                        synchronized ( o ){
                                if ( totalTickets > 0 ){
                                        String name = Thread . currentThread (). getName ();
                                        System . out . println ( name + " 售卖火车票: " +
                                        totalTickets );
                                        totalTickets -- ;
                                }
                        }
                        if ( totalTickets == 0 ) break ;
                                try {
                                        Thread . sleep ( 100L );
                                } catch ( InterruptedException e ) {
                                        e . printStackTrace ();
                                }
                        }
                }
        }
}
synchronized锁实现原理
        Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.
        同步是围绕称为内部锁或监视器锁的内部实体构建的。 (API 规范通常将此实体简称为 监视器 。)内在锁在同步的两个方面都起作用:强制对对象状态的独占访问并建立对可见性至关重要的事前关联。
        Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
        每个对象都有一个与之关联的固有锁。按照约定,需要对对象的字段进行独占且一致的访问的线程必须在访问对象之前先获取对象的内在锁,然后在完成对它们的使用后释放该内在锁。据说线程在获取锁和释放锁之间拥有内部锁。只要一个线程拥有一个内在锁,其他任何线程都无法获得相同的锁。另一个线程在尝试获取锁时将阻塞。
        When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.
        当线程释放内在锁时,该动作与任何随后的相同锁获取之间将建立事前发生的关系。
        When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
        当线程调用同步方法时,它会自动获取该方法对象的内在锁,并在方法返回时释放该内锁。 即使返回是由未捕获的异常引起的,也会发生锁定释放。

5. 线程同步-Lock

        Synchronized code relies on a simple kind of reentrant lock. This kind of lock is easy to use, but has many limitations.
        同步代码依赖于一种简单的可重入锁。这种锁易于使用,但有很多限制。
        Lock objects work very much like the implicit locks used by synchronized code. As with implicit locks, only one thread can own a Lock object at a time.
        锁对象的工作方式非常类似于同步代码所使用的隐式锁。与隐式锁一样,一次只能有一个线程拥有一个Lock对象。
        The biggest advantage of Lock objects over implicit locks is their ability to back out of an attempt to acquire a lock. The tryLock method backs out if the lock is not available immediately or before a timeout expires (if specified). The lockInterruptibly method backs out if another thread sends an interrupt before the lock is acquired.
        与隐式锁相比,Lock 对象的最大优点是它们能够回避获取锁的企图。如果该锁不能立即或在超时到期之前不可用,则tryLock 方法将撤消(如果指定)。如果另一个线程在获取锁之前发送了中断,则lockInterruptibly方法将退出。
示例
import java . util . concurrent . locks . Lock ;
import java . util . concurrent . locks . ReentrantLock ;
public class LockDemo {
        public static void main ( String [] args ) {
                SaleTask task = new SaleTask (); // 一个成员
                Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员
                Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员
                Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员
                t1 . start ();
                t2 . start ();
                t3 . start ();
        }
        static class SaleTask implements Runnable {
                private int totalTickets = 10 ; // 售卖 10 张火车票
                private Lock lock = new ReentrantLock (); // 创建一个可重入锁
                @Override
                public void run () {
                        while ( true ){
                                //尝试获得锁
                                if ( lock . tryLock ()){
                                        try {
                                                if ( totalTickets > 0 ){
                                                        String name = Thread . currentThread (). getName ();
                                                        System . out . println ( name + " 售卖火车票: " +                                                                                         totalTickets );
                                                        totalTickets -- ;
                                                }
                                        } finally {
                                                lock . unlock (); // 解锁
                                }
                        }
                        if ( totalTickets == 0 ) break ;
                                try {
                                        Thread . sleep ( 100L );
                                } catch ( InterruptedException e ) {
                                        e . printStackTrace ();
                                }
                        }
                }
        }
}

6. 线程通信

Object类中的通信方法
public final native void notify (); // 唤醒一个在监视器上等待的线程
public final native void notifyAll (); // 唤醒所有在监视器上等待的线程
public final void wait () throws InterruptedException ; // 等待
public final native void wait ( long timeout ) throws InterruptedException ; // 计时等待
public final void wait ( long timeout , int nanos ) throws
InterruptedException ; // 计时等待
案例
小明每次没有生活费了就给他的爸爸打电话,他的爸爸知道了后就去银行存钱,钱存好了之后就通知小明去取。
分析
  • a. 存钱和取钱都有一个共用的账户
  • b. 存钱后需要通知取钱,然后等待下一次存钱
  • c.取钱后需要通知存钱,然后等待下一次取钱
代码实现
package com . wq . thread . interact ;
public class Account {
        private String name ;
        private double balance ;
        private boolean hasMoney = false ; // 存钱标志
        public Account ( String name ) {
                this . name = name ;
        }
        public synchronized void store ( double money ){
                if ( hasMoney ){ // 已经存钱了
                        System . out . println ( name + " 的老爸等待通知存钱 " );
                        try {
                                wait ();
                        } catch ( InterruptedException e ) {
                                e . printStackTrace ();
                        }
                } else {
                        balance += money ;
                        System . out . println ( name + " 的老爸存了 " + money + " 元钱 " );
                        hasMoney = true ;
                        notifyAll (); // 通知取钱
                }
        }
        public synchronized void draw ( double money ){
                if ( hasMoney ){ // 已经存钱了
                        if ( balance < money ){ // 余额不足
                                System . out . println ( name + " 向他老爸控诉没有钱了 " );
                                hasMoney = false ;
                                notify (); // 通知他老爸存钱
                        } else {
                                balance -= money ;
                                System . out . println ( name + " 取了 " + money + " 元钱 " );
                        }
                } else { // 没有存钱
                        try {
                                System . out . println ( name + " 等待他老爸存钱 " );
                                wait (); // 等待存钱
                        } catch ( InterruptedException e ) {
                                e . printStackTrace ();
                        }
                }
        }
}
package com . wq . thread . interact ;
/**
* 存钱任务
*/
public class StoreTask implements Runnable {
        private Account account ;
        private double money ;
        public StoreTask ( Account account , double money ) {
                this . account = account ;
                this . money = money ;
        }
        @Override
        public void run () {
                while ( true ){
                        account . store ( money );
                        try {
                                Thread . sleep ( 500 );
                        } catch ( InterruptedException e ) {
                                e . printStackTrace ();
                        }
                }
        }
}
package com . wq . thread . interact ;
/**
* 取钱任务
*/
public class DrawTask implements Runnable {
        private Account account ;
        private double money ;
        public DrawTask ( Account account , double money ) {
                this . account = account ;
                this . money = money ;
        }
        @Override
        public void run () {
                while ( true ){
                        account . draw ( money );
                        try {
                                Thread . sleep ( 500 );
                        } catch ( InterruptedException e ) {
                                e . printStackTrace ();
                        }
                }
        }
}
package com . wq . thread . interact ;
public class AccountTest {
        public static void main ( String [] args ) {
                Account account = new Account ( " 小明 " );
                Thread t1 = new Thread ( new StoreTask ( account , 500 ));
                Thread t2 = new Thread ( new DrawTask ( account , 1000 ));
                t1 . start ();
                t2 . start ();
        }
}

7. 线程状态

public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW ,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE ,
/**
* Thread state for a thread blocked waiting for a monitor lock.
*/
BLOCKED ,
/**
* Thread state for a waiting thread.
*/
WAITING ,
/**
* Thread state for a waiting thread with a specified waiting time.
*/
TIMED_WAITING ,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED ;
}
线程状态转换图

更多参考:

Java SE入门及基础(59)& 线程的实现(上) & 线程的创建方式 & 线程内存模型 & 线程安全-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1881082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

老师如何将期末成绩单独发给家长?

老师们&#xff0c;期末季又到了&#xff0c;又要面临一个重要而微妙的任务——发放期末成绩。在这个信息爆炸的时代&#xff0c;如何安全、高效、又充满人情味地将成绩单送到家长手中&#xff0c;成了我们的一项挑战。今天&#xff0c;我就来和大家分享一些小技巧&#xff0c;…

Wp-scan一键扫描wordpress网页(KALI工具系列三十二)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

LeetCode 算法:二叉树的右视图 c++

原题链接&#x1f517;&#xff1a;二叉树的右视图 难度&#xff1a;中等⭐️⭐️ 题目 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4…

某易六月实习笔试

第一题 下面代码需要更改的地方已指出。 解题思路 模拟题&#xff0c;用双指针记录双方当前式神&#xff0c;再记录一下当前谁先手&#xff0c;直到有一方指针越界。 把下面代码now1变为now(now1)%2就行。 第二题 解题思路 01背包变种&#xff0c;只是背包的容量变为多个维度…

清华大学世界排名:2025QS世界大学排名第20名

近日&#xff0c;国际高等教育研究机构QS Quacquarelli Symonds正式发布了2025QS世界大学排名&#xff0c;其中麻省理工学院连续第13年蝉联榜首&#xff0c;北京大学排名由去年的全球第17上升至全球第14名&#xff0c;清华大学位列2025QS世界大学排名第20名&#xff0c;以下是查…

【高级篇】分区与分片:MySQL的高级数据管理技术(十三)

引言 在上一章,我们探讨了MySQL的主从复制与高可用性,这是构建健壮数据库架构的基石。现在,让我们深入到更高级的主题——分区与分片,这些技术对于处理大规模数据集和提升数据库性能至关重要。我们将详细介绍表分区的概念、类型及分片技术的应用,为下一章讨论MySQL集群与…

【硬件视界2】CPU和GPU:计算机架构的双子星

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、CPU (中央处理器)①主要作用②特点 2、 GPU (图形处理…

架构师篇-9、从事件风暴到微服务设计的落地过程

用户付款功能第二个版本的设计实现 单一职责原则&#xff08;SRP&#xff09; 软件系统中的每个元素只完成自己职责内的事&#xff0c;将其他的事交给别人去做“职责”通常人理解为一个事情&#xff0c;与该事情相关的事都是它的责任 一个职责是软件变化的一个原因 第二次需求…

2024年06月CCF-GESP编程能力等级认证Scratch图形化编程二级真题解析

本文收录于《Scratch等级认证CCF-GESP图形化真题解析》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(共 10 题,每题 3 分,共 30 分) 第1题 小杨父母带他到某培训机构给他报名参加 CCF 组织的 GESP 认证考试的第 1 级,那他可以选择的认证语言有几…

Apache Ranger 2.4.0 集成hadoop 3.X(Kerbos)

1、安装Ranger 参照上一个文章 2、修改配置 把各种plugin转到统一目录&#xff08;源码编译的target目录下拷贝过来&#xff09;&#xff0c;比如 tar zxvf ranger-2.4.0-hdfs-plugin.tar.gz tar zxvf ranger-2.4.0-hdfs-plugin.tar.gz vim install.properties POLICY_MG…

基于vue脚手架创建的图书商城

功能简介 此项目包括首页, 搜索列表, 商品详情, 购物车, 订单, 支付, 用户登陆/注册等多个子模块&#xff0c;使用 Vue 全家 桶ES6WebpackAxios 等技术&#xff0c;采用模块化、组件化、工程化的模式开发。 功能模块图 2.1首页 2.2.搜索列表 2.3.商品详情 2.4.购物车 2.5.支…

flask的基本使用2

上一篇我们介绍了基本使用方法 flask使用 【 1 】基本使用 from flask import Flask# 1 实例化得到对象 app Flask(__name__)# 2 注册路由--》写视图函数 app.route(/) def index():# 3 返回给前端字符串return hello worldif __name__ __main__:# 运行app&#xff0c;默认…

正则表达式阅读理解

这段正则表达式可以匹配什么呢&#xff1f; 超级复杂的一段正则表达式。 ((max|min)\\s*\\([^\\)]*(,[^\\)]*)*\\)|[a-zA-Z][a-zA-Z0-9]*(_[a-zA-Z][a-zA-Z0-9]*)?(\\*||%)?|[0-9](\\.[0-9])?|\\([^\\)]*(,[^\\)]*)*\\))(\\s*[-*/%]\\s*([a-zA-Z][a-zA-Z0-9]*(_[a-zA-Z][…

Servlet_Web小结

1.web开发概述 什么是服务器&#xff1f; 解释一&#xff1a;服务器就是一款软件,可以向其发送请求,服务器会做出一个响应. 可以在服务器中部署文件,让他人访问 解释二&#xff1a;也可以把运行服务器软件的计算机也可以称为服务器。 web开发&#xff1a; 指的是从网页中向后…

vue2实例实现一个初步的vue-router

vue2实例实现一个初步的vue-router 实现源码&#xff1a;vue2-review 1.App.vue 2.router目录下的index.js 3.自己实现的x-router.js 4.自己实现的xrouter-view.js 5.自己实现的xrouter-link.js 6.效果 微信公众号&#xff1a;刺头拾年

Unity Shader 极坐标

Unity Shader 极坐标 前言项目简单极坐标极坐标变体之方形极坐标变体之圆形拉花 鸣谢 前言 极坐标记录 项目 简单极坐标 极坐标变体之方形 极坐标变体之圆形 拉花 鸣谢 【菲兹杂货铺】【Unity Shader教程】极坐标实现以及极坐标的两种变体

VUE的快速使用

使用步骤 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&…

【LeetCode】 740. 删除并获得点数

这真是一道好题&#xff01;这道题不仅考察了抽象思维&#xff0c;还考察了分析能力、化繁为简的能力&#xff0c;同时还有对基本功的考察。想顺利地做出这道题还挺不容易&#xff01;我倒在了第一步与第二步&#xff1a;抽象思维和化繁为简。题目的要求稍微复杂一些&#xff0…

抖音短视频矩阵系统开发部署全攻略技术分享

抖音短视频矩阵系统源码开发搭建技术开源分享 一、获取源码与环境配置 我们需要获取抖音短视频矩阵系统的源码。 这可以通过多种方式实现&#xff0c;包括但不限于利用搜索引擎查询或访问专业的开源社区。一旦源码到手&#xff0c;接下来的步骤便是准备服务器环境。对于本系统…

介绍两个压测工具pgbench\sysbench,可视化监控工具NMON

性能评估做不好&#xff0c;开会又领导点名叼了。/(ㄒoㄒ)/~~ /(ㄒoㄒ)/~~ /(ㄒoㄒ)/~~ 挨叼了&#xff0c;也要写文章&#xff0c;记录下我的笔记。 写篇文章 对数据库、OS性能的性能评估&#xff0c;需要选择合适的压测工具&#xff0c;给找出数据库的运行瓶颈 pgbench 这是…