多线程【基本概念、Synchronized、互斥/死锁/释放锁】

第十七章、多线程基础

1、程序(programm)

1.1、概念:

完成特定的任务、用某种语言编写的一组指令的集合。一段静态代码。

2、进程

1、进程是指运行中的程序,比如qq使用,就是一个进程,迅雷又是一个进程。就会为其分配内存空间

2、进程是查询的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生,存在和消亡的过程。

3、线程相关概念

3.1、线程由进程创建的,是进程的一个实体

3.2、单线程

1、同一时刻,只允许执行一个线程

3.3、多线程

1、同一时刻,可以指向多个线程。(一心N用)

3.4、并发

1、同一时刻,多个任务交通执行。

3.5、并行

1、同一时刻,多个任务同时执行。

4、线程的基本使用(两种方式)

4.1、 继承Thread类

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
  3. 创建Thread类的子类的对象
  4. 通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
4.1.2、理解低层

1、调用start ()方法,start()方法中有start0()方法。start0()是本地方法,是JVM机调用,低层实现是c/c++实现。。

2、所以是start0才是真正实现多线程的效果

4.1.3、eg
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.run();
    }
}
class Cat extends Thread {
//    重写thread中的run方法,写自己业务逻辑
//    run Thread 类实现了Runable 接口的run方法
    @Override
    public void run() {
        int count = 0;
        while (true) {
//    每隔一秒,在控制台输出“喵喵,我是小猫咪”
            System.out.println("喵喵,我是小猫咪"+(++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(count==10){
                break;
            }
        }
    }
}

4.2、实现Runnable接口

4.2.1、说明

1、java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。

2、java设计者提供了另一个方式创建线程,就是通过实现Runnable接口来创建线程。

4.2.2、eg
    public static void main(String[] args) {
        T1 t1 = new T1();
        Thread thread1 = new Thread(t1);
        thread1.start();
    }
}
class T1 implements Runnable {
    int count = 0;

    @Override
    public void run() {
        while (true) {
            //每隔1秒输出“hello,world”,输出10次
            System.out.println("hello,world" + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                break;
            }
        }
    }
}

5、继承Thread和实现Runnab的区别

1、从java设计上看,继承继承Thread和实现Runnab接口创建线程本质上没有什么区别,从jdk文档看,Thread本身就实现了Runnable接口

2、实现Runnable接口更加适合多个线程共享一个资源的情况,并且避免了单继承的限制。

6、线程终止

1、线程执行完毕

2、通过使用变量来控制run方法退出的方式停止线程,即通知方式。

(1)利用一个变量,设置boolean来控制,循环。

(2)eg本例子使用set()方法修改。

class T extends Thread{
    int c =0;
    private boolean loop=true;
    @Override
    public void run() {
        while (loop){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("数数开始:"+c);
            c++;

        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

7、线程常用方法

7.1、常用方法1

1、方法

(1)setName //设置线程名称,使其与参数name相同;

(2)getName //返回该线程的名称;

(3)start //使该线程开始执行;Java虚拟机底层调用该线程的start0方法;

(4)run //调用线程对象run方法;

(5)setPriority //更改线程的优先级;

(6)getPriority //获取线程的优先级;

(7)sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行);

(8)interrupt //中断线程,注意不是终止,如果线程正在休眠,则停止休眠,继续执行。

2、例子:

        T t = new T();
//        设置线程名称方法
        t.setName("阿涛");
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();//启动子线程
        System.out.println(t.getName());
        System.out.println("");

//        主线程打印5 hi ,然后中断子线程的睡眠
        for(int i =1;i<=5;i++){
            Thread.sleep(1000);
            System.out.println("hi"+i);
        }
        t.interrupt();//提前结束休息时间,直接中断线程。开始下一个线程
    }
}
class T extends Thread{//自定义线程类

    @Override
    public void run() {
        while(true) {
            for (int i = 0; i < 100; i++) {
//            getName()获取当前线程名称
                System.out.println(Thread.currentThread().getName() + "吃包子~~" + i);
            }
            try {
                System.out.println(Thread.currentThread().getName() + "吃包子累了休息一下");
                Thread.sleep(20000);//休眠时间
            } catch (InterruptedException e) {
//            当该线程执行到一个interrupt方法时,就会catch 一个异常,可以加入自己的业务代码
//            interrupt:被中断
                System.out.println(Thread.currentThread().getName() + "被interruptaaaaaaaaaaaaaaaa");

            }
        }
    }
}

7.2、常用方法2—线程插队、礼让

1、yield:如果CPU忙得过来,则体现不吃礼让

2、join:t1 让大哥t2插队,就在t1里调用join方法

3、例子

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        T2 t2 = new T2();
        t2.start();

        for(int i=1;i<=20;i++){
            Thread.sleep(1000);
            System.out.println("主线程吃了(小弟)"+i+"个包子");
            if(i==5){
                System.out.println("主线程(小弟)让子线程(老大)先吃:");
                t2.join();
                System.out.println("主线程(小弟吃)");
            }
        }
    }
}
class T2 extends Thread{
    @Override
    public void run() {
        for(int i =1;i<=20;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            System.out.println("JoinThread————————"+i);
            System.out.println("子线程吃了"+i+"个包子");
        }
    }
}

7.3、注意事项细节

1、start低层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新线程

2、线程优先级的范围

(1)Max_PRIORITY:10

(2)Min_PRIORITY:1

(3)NORM_PRIORITY:5

3、interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程

4、slee:线程的静态方法,使当前线程休眠

7.4、线程常用方法3—用户线程和守护线程

1、用户线程:也叫工作线程,当线程的任务执行完或通知方式结束

2、守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束

3、最常见的守护线程:垃圾回收机制。

4、注意:守护线程设置要在线程启动之前

5、eg

public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDemonThread myDemonThread = new MyDemonThread();
//        主线程结束后,子线程自动退出。将子线程设置为守护线程即可
        myDemonThread.setDaemon(true);
        myDemonThread.start();
        for(int i=1;i<=10;i++){
            System.out.println("宝强在辛苦的工作!!!");
            Thread.sleep(1000);

        }
    }
}
class MyDemonThread extends Thread{
    @Override
    public void run() {
        for(;;){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("马蓉和宋喆快乐的聊天哈哈哈~~~~");
        }
    }
}

8、线程的生命周期

1、


2、eg

public class ThreadState {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        System.out.println(t.getName()+"状态"+t.getState());
        t.start();
        while(Thread.State.TERMINATED !=t.getState()){
            System.out.println(t.getName()+"状态"+t.getState());
            Thread.sleep(500);
        }
    }
}
class T extends Thread{
    @Override
    public void run() {
        while(true) {
            for (int i = 0; i < 10; i++) {
                System.out.println("hi" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}
//结果
Thread-0状态NEW
Thread-0状态RUNNABLE
hi0
Thread-0状态TIMED_WAITING
hi1
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi2
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi3
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi4
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi5
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi6
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi7
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi8
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING
hi9
Thread-0状态TIMED_WAITING
Thread-0状态TIMED_WAITING

9、Synchronized关键字

9.1、线程同步机制

1、同步:在多线程中,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,保证数据的完整性。

9.2、同步具体方法-Synchronized

1、同步代码块

synchronized(对象){//得到对象的锁,才能操作同步代码
    //需要被同步代码;

}

2、synchronized还可以放在方法声明中,表示整个方法-为同步方法

public synchronized void m(String name){
    //需要被同步的代码
}

3、理解

(1)小伙伴上厕所,关厕所门,上完厕所后开门,其他小伙伴就可以上厕所了

4、例子

class SellTicket03 implements Runnable{
    private int tickNum =100;
    private boolean loop =true;//定义一个变量,控制run方法
    //同步方法,在同一时刻,只能一个线程来执行同步方法
    public synchronized void m(){
        if(tickNum<=0){
            System.out.println("售票结束");
            loop = false;
            return;
        }
//            休眠一会50毫秒
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        --tickNum;
        System.out.println("窗口:"+Thread.currentThread().getName()+"售出一张票"+"剩余票数:"+tickNum);
    }

    @Override
    public  void run() {
        while(loop){
            m();//卖票方法,同步
        }
    }
}

10、互斥锁

10.1、基本介绍

1、java引入对象互斥锁的概念,来保证共享数据操作的完整性

2、每个对象都对应一个可称为”互斥锁“的标记,这个标记用来保证在任一时刻,只能有一个线程访问对象(理解:我拿到别人就没有)

3、关键字sychronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问

4、同步的局限性:导致出现中的执行效率要降低

5、同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一对象),锁只在该对象

6、同步方法(静态的)的锁为当前类本身,所在该类中

10.2、eg

public class SynchronizedDemo {

    // 修饰实例方法
    synchronized void updateData() {
        // 业务代码
    }

    // 修饰静态方法
    synchronized static void retrieveData() {
        // 业务代码
    }

    // 修饰代码块
    Object obj = new Object();

    void createData() {
        synchronized(obj) {
            // 业务代码
        }
    }
}
public class DemoSellTicket {
    public static void main(String[] args) {
        SellTicket04 sellTicket04 = new SellTicket04();
        SellTicket04 sellTicket041 =new SellTicket04();
        SellTicket04 sellTicket042 = new SellTicket04();
        sellTicket04.start();
        sellTicket041.start();
        sellTicket042.start();
    }
}
class SellTicket04 extends Thread {
    private  int tickNum =100;
    private boolean loop =true;
    public  synchronized void sell1(){

        if(tickNum<=0){
            System.out.println("售票结束");
            loop =false;
            return;
        }
//            休眠一会50毫秒
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        --tickNum;
        System.out.println("窗口:"+Thread.currentThread().getName()+"售出一张票"+"剩余票数:"+tickNum);
    }
    @Override
    public  void run() {
        while(loop){
            sell1();
        }
    }
}

10.3、注意事项和细节

1、同步方法如果没有使用static修饰:默认锁对象为this

2、如果方法使用static修饰,默认锁对象:当前类.class

3、实现的落地步骤

(1)分析需要上锁的代码

(2)选择同步代码块或同步方法

(3)要求多个线程的锁对象为同一个

11、线程的死锁

11.1、基本介绍

1、多个线程都占用了对方的锁资源,但不肯想让,导致了死锁,在编程是一定要避免死锁的发生。

11.2、eg

public class DeadLock {
    public static void main(String[] args) {
//        模拟死锁现象
        DeadLockDemo deadLockDemo =new DeadLockDemo(true);
        deadLockDemo.setName("A线程");
        DeadLockDemo deadLockDemo1 = new DeadLockDemo(false);
        deadLockDemo1.setName("B线程");
        deadLockDemo1.start();
        deadLockDemo.start();

    }
}
class DeadLockDemo extends Thread{
    static Object o1= new Object();//保证多线程共享一个对象,使用static
    static Object o2 = new Object();
    boolean flag;

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

    @Override
    public void run() {
        if(flag){
            synchronized (o1){//对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName()+"进入1");
                synchronized (o2){//让li获得监控
                    System.out.println(Thread.currentThread().getName()+"进入2");
                }
            }
        }else{
            synchronized (o2){
                System.out.println(Thread.currentThread().getName()+"进入3");
                synchronized (o1){
                    System.out.println(Thread.currentThread().getName()+"进入o4");
                }
            }
        }
    }
}

12、释放锁

12.1、下面操作释放锁

1、当前线程的同步方法、同步代码块执行完毕

2、当前线程在同步代码块、同步方法中遇到break、return

3、当前线程在同步代码块、同步方法中出现了为出现的Error或Exception,导致异常结束

4、当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

12.2、下面操作不会释放锁

1、线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁

2、线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁

3、尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用

13、课后练习

1、第一题

(1)在main方法中启动两个线程

(2)第1个线程循环随机打印100以内的证书

(3)直到第2个线程从键盘读取了“Q"命令。

2、第二题

(1)有2个用户分别从同一张卡上取钱(总额10000)

(2)每次都取1000,当余额不足时,就不能取款

(3)不能超取现象—》线程同步问题

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇