线程(Thread)的使用方法和锁(同步代码块,lock锁)的问题

news/2024/9/22 18:58:31/

多线程:
        进程:
            正在运行的程序,是系统进行资源分配和调用的独立单位。
            每一个进程都有它自己的内存空间和系统资源。
            理解:一个正在运行的软件
        线程:
            是进程中的单个顺序控制流,是一条执行路径
            一个进程如果只有一条执行路径,则称为单线程程序。
            一个进程如果有多条执行路径,则称为多线程程序。
            举例:阿里云盘(进程)中多个同时进行的任务,每一个任务可以看作一个线程

    1、如何创建一个线程对象呢?
        a. 自定义线程类继承Thread类,重写run方法
        b. 自定义线程类实现Runnable接口,实现run方法

    2、如何启动一个线程呢?
        调用start()方法启动

    Thread无参构造方法

     Thread() 分配一个新的 Thread对象。


    注意:
        1、启动一个线程的时候,若直接调用run方法,仅仅是普通的对象调用方法,按照自上而下的顺序执行,底层不会额外的创建一个线程再执行
        2、从执行的结果上来看,java线程之间是抢占式执行的,谁先抢到cpu执行权谁就先执行
        3、每次运行的结果顺序不可预测的,完全随机的
        4、每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。只是优先级高的先执行的概率大一点,并不代表一定先执行,完全是随机。

    Thread类中的成员方法:


        1、public final String getName()  获取线程对象的名字
        2、设置线程对象名字的方式:
            a. 通过父类的有参构造方法,在创建线程对象的时候设置名字
            b. 线程对象调用setName(String name)方法,给线程对象设置名字
        3、获取线程的等级
            getPriority() 默认优先级都是5
        4、设置线程优先级,setPriority(int i),在启动之前设置  [1,10]
            注意不是优先级高的一定先执行,只是可能性变高了。

Thread中sleep()、stop()、join()、yield()、setDaemon()、wait(),notify()的方法使用:
sleep()的使用:线程休眠

    线程控制:休眠线程
    当线程处于休眠状态的时候,该线程就没有cpu执行权了,若这时还有其他的线程,会被抢走cpu执行权。

代码如下:

java">class SleepThread extends Thread {@Overridepublic void run() {System.out.println(getName() + " 睡着了。。。。");try {Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName()+" 睡醒了。。。。");}
}public class ThreadSleepDemo1 {public static void main(String[] args) {SleepThread t1 = new SleepThread();t1.setName("光头强");t1.start();}
}

stop()的使用:线程中断

java">class StopThread extends Thread {@Overridepublic void run() {System.out.println(getName() + " 睡着了。。。。");try {Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName()+" 睡醒了。。。。");}
}public class ThreadStopDemo1 {public static void main(String[] args) {StopThread t1 = new StopThread();t1.setName("熊大");t1.start();try {Thread.sleep(2000);
//            t1.stop();t1.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}
}

join()的使用:线程加入
java">class JoinThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 10; i++) {System.out.println(getName() + " - " + i);}}
}public class ThreadJoinDemo1 {public static void main(String[] args) {JoinThread t1 = new JoinThread();JoinThread t2 = new JoinThread();JoinThread t3 = new JoinThread();t1.setName("光头强");t2.setName("熊大");t3.setName("熊二");t1.start();try {t1.join(); // 其他线程等待该线程执行结束,其他线程之间会进行抢占式执行} catch (InterruptedException e) {e.printStackTrace();}t2.start();t3.start();}
}

yield()的使用:线程礼让

只是让结果看起来更加均匀一些,并不是我们日常生活中理解的完全谦让

java"> 礼让线程yield()只是为了运行结果看起来均匀一些class YieldThread extends Thread{@Overridepublic void run() {for(int i=1;i<200;i++){System.out.println(getName()+" - "+i);Thread.yield();}}
}public class ThreadYieldDemo1 {public static void main(String[] args) {YieldThread t1 = new YieldThread();YieldThread t2 = new YieldThread();t1.setName("民哥");t2.setName("原神哥");t1.start();t2.start();}
}
setDaemon()后台线程:

        用户线程
        守护线程
    在启动之前,设置一下若一个进程中没有用户线程,守护线程也没有必要存在。

java">class DaemonThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 200; i++) {System.out.println(getName() + " - " + i);}}
}public class ThreadDaemonDemo1 {public static void main(String[] args) {DaemonThread t1 = new DaemonThread();DaemonThread t2 = new DaemonThread();DaemonThread t3 = new DaemonThread();t1.setName("刘备");t2.setName("关羽");t3.setName("张飞");t2.setDaemon(true);t3.setDaemon(true);t1.start();t2.start();t3.start();}
}
wait()和notify()的使用:可用于生产者和消费者模型中,wait()就是等待,等待某个程序的完成后,再进行解锁notify(),再让其他程序运行,wait()等待期间,属于程序阻塞

 使用Runnable的方式实现:售票问题(SellTickets)

 为了模拟更加真实的售票情况,我们加入延迟
    问题:
        我们加入了延迟之后,发现
        a. 有重复售卖同一张票的情况(原因1)
        b. 还出现了一个不该出现的票数据,比如第0张票,第-1张票(原因2)
    原因:
        1. cpu小小的时间片,足以让程序执行很多次
        2. 线程的执行具有随机性,且是抢占式执行的

 现象:线程不安全的现象
        如何判断一个程序是否存在线程不安全的现象呢?
        三要素(同时满足):
            1、是否存在多线程环境?
            2、是否存在共享数据?
            3、是否存在多条语句操作着共享数据?
    如何解决线程不安全的现象?
        1、同步代码块
        2、lock锁

    解决方案1:加入同步代码块
        synchronized(对象){
            操作共享数据的代码
        }
      这里的对象,可以是任意一个new出来的对象,但是要保证多个线程之间是同一个对象。

   synchronized的使用
        1、同步代码块 - 锁对象 - 任意一个对象,前提是多个线程对象共享一个
        2、同步方法 - 锁对象 - this
        3、同静态方法 - 锁对象 - 当前类的class文件对象

    解决方案2:lock锁,利用ReentrantLock类创建锁对象,要求多个线程对象共享一个
        不需要考虑锁对象是谁了。
 
同步代码块1:锁任意对象--Object
java">class Window implements Runnable{private static int tickets = 100;private Object object = new Object();@Overridepublic void run() {while (true){synchronized (object){if(tickets>0){try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票......");}}}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window,"窗口1");Thread w2 = new Thread(window,"窗口2");Thread w3 = new Thread(window,"窗口3");w1.start();w2.start();w3.start();}
}
同步代码块2:锁对象--this
java">class Window implements Runnable {private static int tickets = 100;
//    private Object object = new Object();private int i = 0;@Overridepublic void run() {while (true) {if (i % 2 == 0) {synchronized (this) {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}} else {sellTicket();}i++;}}//同步方法,将synchronized在方法定义上出现
//    public synchronized void sellTicket() {
//        if (tickets > 0) {
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
//        }
//    }public static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
同步代码块3:锁对象--当前类的class文件对象
java">class Window implements Runnable {private static int tickets = 100;
//    private Object object = new Object();private int i = 0;@Overridepublic void run() {while (true) {if (i % 2 == 0) {synchronized (Window.class) {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}} else {sellTicket();}i++;}}//同步方法,将synchronized在方法定义上出现
//    public synchronized void sellTicket() {
//        if (tickets > 0) {
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
//        }
//    }public static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
lock锁:不用考虑锁对象
java">class Window implements Runnable {private static int tickets = 100;//    private Object object = new Object();private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {lock.lock(); // 加锁if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}lock.unlock(); // 释放锁}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
 死锁情况:

分两个类:Locks对象类,测试类,  死锁的问题:线程之间存在相互等待的现象

Locks对象类:

java">
import java.util.concurrent.locks.ReentrantLock;public class Locks {private Locks(){}public static final ReentrantLock lock1 = new ReentrantLock();public static final ReentrantLock lock2 = new ReentrantLock();
}

测试类:

java">class Person extends Thread{private boolean flag;public Person(boolean flag) {this.flag = flag;}@Overridepublic void run() {if(flag){synchronized (Locks.lock1){System.out.println("if lock1");// p1synchronized (Locks.lock2){System.out.println("if lock2");}}}else {synchronized (Locks.lock2){System.out.println("else lock2");// p2synchronized (Locks.lock1){System.out.println("else lock1");}}}}
}public class DieLockDemo {public static void main(String[] args) {Person p1 = new Person(true);Person p2 = new Person(false);p1.start();p2.start();}
}


http://www.ppmy.cn/news/1512292.html

相关文章

ELK基础搭建

一、认识ELK ELK是一套开源的日志分析系统&#xff0c;由elasticsearchlogstashKibana组成。 官网说明&#xff1a;https://www.elastic.co/cn/products 首先: 先一句话简单了解 E&#xff0c;L&#xff0c;K 这三个软件 elasticsearch: 分布式搜索引擎 logstash: 日志收集与…

如何用CWE API 来减轻软件产品中的安全风险

本文分享自华为云开发者社区《用CWE API 减轻软件产品中的安全风险》作者&#xff1a; Uncle_Tom 1. CWE REST API 推出的目的 8 月 8 号&#xff0c;CWE™ 计划推出了“CWE REST API”。 CWE™计划由美国网络安全与基础设施安全局(Cybersecurity & Infrastructure Secur…

一口气学完Python编程语言的基础内容

文章目录 第1章 Python简介1.1 Python简介1.2 Python历史1.3 Python特点1.4 Python的应用场景1.5 Python的版本 第2章 Python环境搭建2.1 Python软件安装2.2 编辑器安装 第3章 Python基础语法3.1 第一个Python程序3.1.1 使用 Python 命令行3.1.2 使用 IPython3.1.3 使用 PyChar…

ID3算法详解:构建决策树的利器

目录 引言 ID3算法概述 算法基础 信息熵 ​编辑 信息增益 ID3算法步骤 决策树 概念: 核心&#xff1a; 节点 1. 根节点 2. 非叶子节点 3. 叶子节点 引言 在机器学习领域&#xff0c;决策树是一种非常流行的分类和回归方法。其中&#xff0c;ID3算法作为决策树算法…

【jvm】直接引用

目录 1. 说明2. 形式3. 特点4. 生成过程5. 作用 1. 说明 1.在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;直接引用&#xff08;Direct Reference&#xff09;是相对于符号引用&#xff08;Symbolic Reference&#xff09;而言的&#xff0c;它是指向内存中实际存在的…

PostgreSQL案例:planning time超长问题分析

问题分析概述 库总是OOM&#xff0c;分析到是执行计划生成有问题&#xff0c;planning time 1秒&#xff0c;planning shared hit 100w。一通分析&#xff0c;定位到是统计信息基表pg_statistic膨胀&#xff0c;由于会话首次SQL执行时的CatCacheMiss&#xff0c;导致backend访…

Python版《超级玛丽+源码》-Python制作超级玛丽游戏

小时候最喜欢玩的小游戏就是超级玛丽了&#xff0c;有刺激有又技巧&#xff0c;通关真的很难&#xff0c;救下小公主还被抓走了&#xff0c;唉&#xff0c;心累&#xff0c;最后还是硬着头皮继续闯&#xff0c;终于要通关了&#xff0c;之后再玩还是没有那么容易&#xff0c;哈…

React 学习——useImperativeHandle,暴漏子组件中的方法

暴露子组件的方法&#xff1a; import { forwardRef,useRef,useImperativeHandle } from react;const Input forwardRef((props,propRef)>{const sonRef useRef(null);const focusHandle () > {console.log(父组件调用子组件的方法);sonRef.current.focus();}// 暴露…