首页 > 其他分享 >线程(Thread)的使用方法和锁(同步代码块,lock锁)的问题

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

时间:2024-08-20 20:57:28浏览次数:7  
标签:Thread lock void class 线程 new public

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

    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执行权。

代码如下:

class SleepThread extends Thread {
    @Override
    public 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()的使用:线程中断

class StopThread extends Thread {
    @Override
    public 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()的使用:线程加入
class JoinThread extends Thread {
    @Override
    public 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()的使用:线程礼让

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

 礼让线程
        yield()只是为了运行结果看起来均匀一些

class YieldThread extends Thread{
    @Override
    public 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()后台线程:

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

class DaemonThread extends Thread {
    @Override
    public 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
class Window implements Runnable{
    private static int tickets = 100;
    private Object object = new Object();

    @Override
    public 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
class Window implements Runnable {
    private static int tickets = 100;
//    private Object object = new Object();
    private int i = 0;


    @Override
    public 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文件对象
class Window implements Runnable {
    private static int tickets = 100;
//    private Object object = new Object();
    private int i = 0;


    @Override
    public 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锁:不用考虑锁对象
class Window implements Runnable {
    private static int tickets = 100;
    //    private Object object = new Object();
    private ReentrantLock lock = new ReentrantLock();


    @Override
    public 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对象类:


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();
}

测试类:

class Person extends Thread{
    private boolean flag;

    public Person(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (Locks.lock1){
                System.out.println("if lock1");
                // p1
                synchronized (Locks.lock2){
                    System.out.println("if lock2");
                }
            }
        }else {
            synchronized (Locks.lock2){
                System.out.println("else lock2");
                // p2
                synchronized (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();
    }
}

标签:Thread,lock,void,class,线程,new,public
From: https://blog.csdn.net/ABU009/article/details/141334473

相关文章

  • tcp多个客户端访问服务端,运用多线程
    客户端packagecom.shujia.day20.tcpdemo3;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.Socket;importjava.util.Scanner;/*1:建立客户端的Socket服务,并明确要连接的服务器。2:如果连接建立成功,就表明,已经建立了数据传输的通......
  • Java笔试面试题AI答之线程(2)
    文章目录7.如何确保N个线程可以访问N个资源同时又不导致死锁?1.资源排序与顺序访问2.资源分配策略3.避免占用并等待4.引入超时机制5.死锁检测与解决6.使用高级并发工具7.编程实践8.Java方法可以同时即是static又是synchronized的吗?9.什么是Java多线程同步?10......
  • Java线程池详解
    Java线程池详解线程池解释线程池采用了池化思想,能够有效的管理线程的生命周期,减少了每次获取资源的消耗,提高了资源的利用率。类似池化实现还有数据库连接池、HTTP连接池等好处减少了线程创建和销毁的开销提高了响应速度使得线程更加方便管理常见使用场景量大处理时间......
  • 【Redis】Redis线程与IO模型—(三)
    Redis线程与IO模型一、Redis单线程二、多路复用机制三、Redis6.0多线程特性四、IO多线程配置一、Redis单线程通常说Redis是单线程,主要是指Redis的网络IO和键值对读写是由一个线程来完成的,其他功能,比如持久化、异步删除、集群数据同步等,是由额外的线......
  • 多任务进程与线程
    多任务进程与线程一、多任务介绍​ 我们生活中有很多事情是同时进行的,比如开车的时候手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的;用程序来模拟:fromtimeimportsleepdefsing():foriinrange(3):print("正在唱歌...%d"%i)sleep(1)defda......
  • show processlist查看Mysql当前正在运行的线程
    showprocesslistshowprocesslist;--或者SELECTid,db,user,host,command,time,state,infofrominformation_schema.PROCESSLISTWHERE1=1--andcommand!='Sleep'ANDHOSTLIKE'%localhost%'orderbytimedescID定义:每个连......
  • kworker和kthread
    kworker和kthread都是Linux内核中的组件,它们在内核中扮演着不同的角色,但也有着一定的联系。kworker定义与功能:定义:kworker是Linux内核中的一个工作线程,用于异步处理工作队列(workqueue)中的任务。这些任务包括但不限于处理硬件中断、文件系统事件、管理系统内存等。功能:kworker......
  • 线程池
    `usingBogus;usingMicrosoft.EntityFrameworkCore;usingMicrosoft.EntityFrameworkCore.Infrastructure;usingMicrosoft.EntityFrameworkCore.Storage;usingMicrosoft.Extensions.DependencyInjection;usingNewtonsoft.Json;usingSystem;usingSystem.Collecti......
  • 两线程读写数组
    #include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<unistd.h>#defineARRAY_SIZE10intshared_array[ARRAY_SIZE];pthread_mutex_tmutex;void*write_data(void*arg){intthread_id=*(int*)arg;......
  • ansible block模块
    目录示例:使用block、rescue和always解释:示例输出:实际应用场景:Ansible中的block功能允许你将多个任务组合在一起,作为一个整体来处理。block提供了一些额外的功能,比如rescue和always,这些可以用来处理错误和执行清理任务。以下是一个简单的block功能的示例:示例:使用blo......