Java---线程讲解(二)

文章目录

    • 1. Runnable接口
    • 2. 卖票案例
    • 3. 同步代码块解决数据安全问题
    • 4. 同步方法解决数据安全问题
    • 5. 线程安全的类
    • 6. Lock锁


1. Runnable接口

 1. 创建线程的另一种方法是声明一个实现Runnable接口的类,之后重写run()方法,然后可以分配类的实例,在创建Thread时作为参数传递,最后启动。

 2. 具体实现Runnable接口:(1) 定义一个MyRunnable实现Runnable接口。 (2) 在MyRunnable中重写run()方法。 (3) 创建MyRunnable类对象。 (4) 创建Thread类的对象,把MyRunnable对象作为构造方法的参数。 (5) 启动线程。

public class MyRunnable implements Runnable{@Overridepublic void run() {for(int i=0;i<100;i++){System.out.println(Thread.currentThread().getName()+":"+i);}}
}public class MyRunnableDemo {public static void main(String[] args) {//创建MyRunnable类对象MyRunnable my=new MyRunnable();//创建Thread类对象,把MyRunnable对象作为参数传进来//Thread(Runnable target)//Thread t1=new Thread(my);//Thread t2=new Thread(my);//Thread(Runnable target, String name)Thread t1=new Thread(my,"线程1");Thread t2=new Thread(my,"线程2");//启动线程t1.start();t2.start();}
}

在这里插入图片描述
 3. 多线程的实现方案有两种:(1) 继承Thread类。 (2) 实现Runnable接口。

  • 实现Runnable接口好处:避免了Java单继承的局限性;适合多个相同程序的代码去处理同一资源的情况,把线程和程序的代码、数据有效分离,较好地体现了面向对象的设计思想。

2. 卖票案例

 1. 需求和思路:

在这里插入图片描述

 2. 代码块:

public class SellTicket implements Runnable{//表示有100张票private int tickets=100;@Overridepublic void run() {while (true){if(tickets>0){System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");tickets--;}}}
}public class SellTicketDemo {public static void main(String[] args) {SellTicket st=new SellTicket();Thread t1=new Thread(st,"窗口1");Thread t2=new Thread(st,"窗口2");Thread t3=new Thread(st,"窗口3");t1.start();t2.start();t3.start();}
}

在这里插入图片描述
 3. 问题分析:看上面结果相同的票会出现三次,为什么呢?请参照下图理解,虽然加上了休眠时间,但是原理是一样的,都是线程抢占CPU执行权导致的。

在这里插入图片描述

3. 同步代码块解决数据安全问题

 1. 如何解决多线程安全问题:(1) 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。 (2) Java提供了同步代码块的方式来解决。

 2. 同步代码块格式:

在这里插入图片描述

 3. 代码块举例:

public class SellTicket implements Runnable{//表示有100张票private int tickets=100;private Object obj= new Object();@Overridepublic void run() {while (true){synchronized (obj) {if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--;}}}}
}public class SellTicketDemo {public static void main(String[] args) {SellTicket st=new SellTicket();Thread t1=new Thread(st,"窗口1");Thread t2=new Thread(st,"窗口2");Thread t3=new Thread(st,"窗口3");t1.start();t2.start();t3.start();}
}

在这里插入图片描述

 4. 同步的好处和弊端:(1) 好处:解决了多线程的数据安全问题。 (2) 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

4. 同步方法解决数据安全问题

 1. 同步方法:就是把synchronized关键字加到方法上。

 2. 格式:修饰符 synchronized 返回值类型 方法名(方法参数){ }

 3. 同步方法的锁对象:this

 4. 代码块举例:

public class SellTicket implements Runnable{//表示有100张票private int tickets=100;private Object obj= new Object();private int x=0;@Overridepublic void run() {while (true){if(x%2==0) {  //这里得是this,否则会出问题synchronized (this) {if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--;}}}else{sellticket();}x++;}}private synchronized void sellticket(){if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--;}}
}public class SellTicketDemo {public static void main(String[] args) {SellTicket st=new SellTicket();Thread t1=new Thread(st,"窗口1");Thread t2=new Thread(st,"窗口2");Thread t3=new Thread(st,"窗口3");t1.start();t2.start();t3.start();}
}

5. 线程安全的类

在这里插入图片描述

6. Lock锁

 1. 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

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

 3. Lock中获得锁和释放锁的方法:void lock():获得锁。void unlock():释放锁。

 4. Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化。

 5. 代码块举例:

public class SellTicket implements Runnable{//表示有100张票private int tickets=100;private Lock lock=new ReentrantLock();@Overridepublic void run(){while (true) {lock.lock();if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");tickets--;}lock.unlock();}}
}public class SellTicketDemo {public static void main(String[] args) {SellTicket st=new SellTicket();Thread t1=new Thread(st,"窗口1");Thread t2=new Thread(st,"窗口2");Thread t3=new Thread(st,"窗口3");t1.start();t2.start();t3.start();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用eclipse导入外部java工程

利用eclipse导入外部java工程&#xff0c;打开eclipse&#xff0c;依次点击File-Import&#xff0c;…按下图依次执行…

Facebook引流脚本的优势与编写教程!

在当今的数字化时代&#xff0c;社交媒体已经成为企业进行营销和推广的重要渠道之一&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;拥有数十亿的用户&#xff0c;为企业提供了无限的引流可能性。 然而&#xff0c;对于企业来说&#xff0c;在Facebook上吸引…

uni-app 微信小程序之好看的ui登录页面(四)

文章目录 1. 页面效果2. 页面样式代码 更多登录ui页面 uni-app 微信小程序之好看的ui登录页面&#xff08;一&#xff09; uni-app 微信小程序之好看的ui登录页面&#xff08;二&#xff09; uni-app 微信小程序之好看的ui登录页面&#xff08;三&#xff09; uni-app 微信小程…

AttributeError: module ‘importlib_resources‘ has no attribute ‘path‘ 解决方案

问题描述 with importlib_resources.path("xx", fname) as p: AttributeError: module importlib_resources has no attribute path 博主使用的是python3.9&#xff0c;看importlib_resources在importlib-resources PyPI中的介绍&#xff0c;开始猜测问题出在pyth…

先验概率和后验概率

先验概率&#xff08;prior probability&#xff09;&#xff1a;是指根据以往经验和分析得到的概率。先验概率不用贝叶斯公式计算。 后验概率&#xff08;posterior probability&#xff09;&#xff1a;指某个事件已经发生&#xff0c;想要计算这个事件是由于某个因素引起的概…

电子秤ADC芯片CS1237技术资料问题合集

问题11&#xff1a;实际应用中&#xff0c;多个称重传感器应该怎么与ADC连接&#xff1f; 解答&#xff1a;如果传感器是测量同一物体&#xff08;例如&#xff1a;厨房垃圾处理器&#xff09;&#xff0c;一般建议使用并联的方式。则相同类型的信号线连接在一起。对于传感器的…

9种伪原创工具推荐,快速提升创作效率

如何让自己的文章在海量信息中脱颖而出&#xff0c;成为一个备受关注的焦点&#xff0c;成为许多创作者迫切思考的问题。在这篇文章中&#xff0c;我将向大家介绍9种伪原创工具&#xff0c;这些工具可以让你的文章轻松升级&#xff0c;更具创意和吸引力。 1.Spinbot&#xff08…

带你解锁Python操作文件的姿势

什么是文件 文件是计算机中用于存储数据的一种数据结构。它可以是文本文件、图像文件、音频文件、视频文件等等。文件由一系列字节组成&#xff0c;每个字节都有一个唯一的地址。文件可以在计算机的硬盘、固态硬盘、光盘等存储介质上存储&#xff0c;并且可以在需要时被读取和…

百面嵌入式专栏(岗位分析)大疆嵌入式工程师【通信/流媒体】

文章目录 一、岗位简介二、解析2.1、网络协议2.2、音视频传输算法2.3、大规模音视频会议或直播系统 三、简历 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; &#x1f4e2;本篇我们将对大疆嵌入式工程师【通信/流媒体】岗位进行分析 。 一、…

系列学习前端之第 4 章:一文精通 JavaScript

全套学习 HTMLCSSJavaScript 代码和笔记请下载网盘的资料&#xff1a; 链接: 百度网盘 请输入提取码 提取码: 6666 1、JavaScript 格式 一般放在 html 的 <head> 标签中。type&#xff1a;默认值text/javascript可以不写&#xff0c;不写也是这个值。 <script typ…

ExecutorService、Callable、Future实现有返回结果的多线程原理解析

原创/朱季谦 在并发多线程场景下&#xff0c;存在需要获取各线程的异步执行结果&#xff0c;这时&#xff0c;就可以通过ExecutorService线程池结合Callable、Future来实现。 我们先来写一个简单的例子—— public class ExecutorTest {public static void main(String[] ar…

【mysql】下一行减去上一行数据、自增序列场景应用

背景 想获取if_yc为1连续账期数据 思路 获取所有if_yc为1的账期数据下一行减去上一行账期&#xff0c;如果为1则为连续&#xff0c;不等于1就为断档获取不等于1的最小账期&#xff0c;就是离当前账期最近连续账期 代码 以下为mysql语法&#xff1a; select acct_month f…