Java线程(基础)

发布时间:2022-07-02 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java线程(基础)脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

目录

  • 线程介绍
    • 进程
    • 线程
      • 单、多线程
      • 并发和并行
  • 线程的使用
    • 创建线程的两种方法
    • 机制说明
    • 举例说明(继承Thread类重写run()方法实现线程)
    • 为什么调用start()不直接调用run()方法F1f;
    • 举例(实现Runnable接口实现线程)
    • 继承Thread和Runnable接口对比
    • 售票系统(出现了超票问题,该怎么解决)
    • 线程终止
  • 线程的常用方法
    • 第一组
    • 第二组
    • 例子
    • 用户线程和守护线程
      • 如何将线程设置为守护线程
  • 线程的生命周期
  • Synchronized(进程同步机制)
    • 同步具体方法-synchronized
    • 使用Synchronized解决售票问题
      • 代码块上加锁
      • 方法上加锁
  • 互斥锁
    • 基本介绍
    • 注意事项
      • 错误示范(锁对象不同)
  • 线程死锁
  • 释放锁和不释放锁情况
  • 本章作业

线程介绍@H_406_118@

Java线程(基础)

进程

Java线程(基础)

线程

Java线程(基础)

单、多线程

1.单线程:同一个时刻,只允许执行一个线程 2.多线程:同一个时刻,可以执行多个线程,比如:一个QQ进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件

并发和并行

Java线程(基础)

线程的使用

创建线程的两种方法

在java中线程来使用有两种方法。 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法

机制说明

Java线程(基础)

当main线程通过start()方法启动一个子线程Thread-0,并不代表主线程会阻塞,它会继续执行,并且与子线程交替执行 主线程结束但是任有子线程不会造成应用程序的结束 主线程可以开多个子线程,子线程也能开新的子线程

Java线程(基础)

Java线程(基础)

举例说明(继承Thread类重写run()方法实现线程)

创建一个进程每隔一秒输出内容,输出8次后停止

package Threaduse;
//演示通过继承Thread 类创建线程
public class test {
    public static void main(String[] args) {
        //创建Cat对象,可以当做线程使用
        cat cat = new cat();
        cat.start();//启动线程-> 最终会执行cat的run方法
    }
}
//1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的run方法
/*
    @override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
 */
class cat extends Thread{
    //重写run()方法

    @Override
    public void run() {//在这里写上自己要实现的业务逻辑
        suPEr.run();
        int times=0;
        while(@H_543_304@true){
            System.out.PRintln("熊猫烧香"+times++);
            //休眠一秒钟(一毫秒为单位),抛出异常ctrl+alt+t
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(times==8){
                break;
            }
        }
    }
}

为什么调用start()不直接调用run()方法?

cat.run()//是一个普通方法,由主线程直接调用run()方法,无法实现线程 cat.start()//启动线程,最终会执行cat.run()方法

Java线程(基础)

Java线程(基础)

start()方法源码解读: run()方法何时执行取决于CPU

Java线程(基础)

举例(实现Runnable接口实现线程)

说明

  1. java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。
  2. java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程

深入内容到之后再讲,先介绍怎么实现

package Threaduse;

public class Thread02 {
    public static void main(String[] args) {
        //底层使用了代理模式(一种设计模式)
        Dog dog = new Dog();
        Thread thread = new Thread(dog);
        thread.start();
    }
}
class Dog implements Runnable {

    @Override
    public void run() {
        //设置自己想设计的逻辑
        int num=0;
        while(true){
            System.out.println("熊猫烧香"+(++num)+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(num==8){
                break;
            }
        }
    }
}

继承Thread和Runnable接口对比

Java线程(基础)

售票系统(出现了超票问题,该怎么解决)

Java线程(基础)

package Threaduse;

public class SellTicketSystem {
    public static void main(String[] args) {
        //使用Thread实现线程
//        SellTicket01 sellTicket01 = new SellTicket01();
//        SellTicket01 sellTicket02 = new SellTicket01();
//        SellTicket01 sellTicket03 = new SellTicket01();
//        sellTicket01.start();
//        sellTicket02.start();
//        sellTicket03.start();
        //使用Runnable接口
        SellTicket02 sellTicket02 = new SellTicket02();
        Thread thread = new Thread(sellTicket02);
        Thread thread2 = new Thread(sellTicket02);
        Thread thread3 = new Thread(sellTicket02);
        thread.start();
        thread2.start();
        thread3.start();
    }
}
class SellTicket01 extends Thread {
    private static int nums=100;
    @Override
    public void run() {
        while(true){
            if(nums<=0){
                System.out.println("票卖完了");
                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("售票口"+Thread.currentThread().getName()+"卖出一张票"+"剩余票数"+(nums--));
        }
    }
}
class SellTicket02 implements Runnable {
private int nums=100;//这里不用定义static,因为始终使用的是同一个SellTicket02生成的对象
    @Override
    public void run() {
        while(true){
            if(nums<=0){
                System.out.println("票卖完了");
                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("售票口"+Thread.currentThread().getName()+"卖出一张票"+"剩余票数"+(nums--));
        }
    }
}

线程终止

●基本说明 1.当线程完成任务后,会自动退出。 2.还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

Java线程(基础)

package Threaduse;

public class Stopthread {
    public static void main(String[] args) throws InterruptedException {
        //需求:启动一个线程t,要求在main线程中去停止线程t,请编程实现.
        如果希望main线程去控制t1 线程的终止,必须可以修改 loop
        // 让t1 退出run方法,从而终止t1线程->通知方式
        让主线程休眠10秒,再通知和线程退出
        T t = new T();
        t.start();
        Thread.sleep(10000);
        t.setLoop(false);
    }
}
class T extends Thread {
    private boolean loop=true;
    @Override
    public void run() {
        while(loop){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程在运行");
        }
    }
    public void setLoop(boolean b){
        loop=b;
    }
}

线程的常用方法

第一组

1.setName /设置线程名称,使之与参数name相同 2.getName//返回该线程的名称 3. start//使该线程开始执行;Java虚拟机底层调用该线程的start()方法 4. run//调用线程对象run方法; 5. setPriorITy //更改线程的优先级 6.getPriority//获取线程的优先级 7.sleep//在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) 8. interrupt //中断线程,但没有结束线程,所以一般用于中断休眠的线程

线程的优先级范围: public static final int MIN_PRIORITY=1; public static final int NORM_PRIORITY=5; public static final int MAX_PRIORITY=10;

package Threaduse;

import javax.crypto.spec.PSource;

public class ThreadMethod {
    public static void main(String[] args) throws InterruptedException {
        //利用主线程设置子线程名,并中断正在休眠的线程
        Z z = new Z();
        z.setName("张李浩");//设置线程名
        z.setPriority(Thread.MIN_PRIORITY);
        z.start();
        //主线程在输出5个i后,interrupt子线程
        for(int i=0;i<5;i++){
            Thread.sleep(1000);
            System.out.println(i);
        }
        z.interrupt();
    }
}
class Z extends Thread {
    @Override
    public void run() {
    //先输出,休眠50秒,interrupt,然后再输出
        while(true){
            int nums=0;
            for(int i=0;i<10;i++){
                System.out.println("线程"+Thread.currentThread().getName()+"正在运行"+(++nums));
            }
            try {
                System.out.println("线程正在休眠");
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                System.out.println("线程被打断了");
            }
        }
    }
}

第二组

yield()线程礼让,假如CPU充足则不一定成功 join()线程插队

Java线程(基础)

例子

Java线程(基础)

package Threaduse;

public class ThreadMethodExercise {
    public static void main(String[] args) throws InterruptedException {
        person person = new person();
        Thread thread = new Thread(person);
        //主线程每个一秒,输出hi,共10次
        for(int i=1;i<=10;i++){
            Thread.sleep(1000);
            System.out.println("hi"+i);
            if(i==5){
                //启动子线程,让其执行完再运行主线程
                thread.start();
                thread.join();
            }
        }
        System.out.println("主线程结束");
    }
}
class person implements Runnable {
    @Override
    public void run() {
        while(true){
            for(int i=1;i<=10;i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("hello"+i);
            }
            System.out.println("子线程结束");
            break;
        }
    }
}

用户线程和守护线程

1.用户线程:也叫工作线程,当线程的任务执行完或通知方式结束 2守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束 3.常见的守护线程:垃圾回收机制

如何将线程设置为守护线程

守护线程当所以用户现场结束,守护线程也自动结束 mydaemoThread.setDaemo(true);//设为守护线程

package com.hspedu.method;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        //如果我们希望当main线程结束后,子线程自动结束
        //,只需将子线程设为守护线程即可
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();

        for( int i = 1; i <= 10; i++) {//main线程
            System.out.println("宝强在辛苦的工作...");
            Thread.sleep(1000);
        }
    }
}

class MyDaemonThread extends Thread {
    public void run() {
        for (; ; ) {//无限循环
            try {
                Thread.sleep(1000);//休眠1000毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("马蓉和宋喆快乐聊天,哈哈哈~~~");
        }
    }
}

线程的生命周期

细分7种,总的来说6种,都对 线程状态。线程可以处于以下6种状态之一: NEW 尚未的线程处于此状态。 RUNNABLE(RUNNABLE状态可以细分为Ready和Running两种状态------>七种) 在Java虚拟机中执行的线程处于此状态。 BLOCKED 被阻塞等待监视器锁定的线程处于此状态。 WAITING 正在等待另一个线程执行特定动作的线程处于此状态。 TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 TERMINATED 已退出的线程处于此状态。

Java线程(基础)

Synchronized(进程同步机制)

1.在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技, 保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。 2.也可以这里理解:线程同步,即当有一个线程在对内存进行操作时, 其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作.

同步具体方法-Synchronized

1.同步代码块 synchronized(对象){//得到对象的锁,才能操作同步代码 //需要被同步代码; } 2. synchronized还可以放在方法声明中,表示整个方法-为同步方法 public synchronized void m (String name){ //需要被同步的代码 }

使用Synchronized解决售票问题

代码块上加锁

class SellTicket03 implements Runnable {
    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;//控制run方法变量
    Object object=new Object(); 
    //同步方法(静态的)的锁为当前类本身
    //老韩解读
    //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
    //2. 如果在静态方法中,实现一个同步代码块.
    /*
        synchronized (SellTicket03.class) {
            System.out.println(";m2");
        }
     */
    public synchronized static void m1() {

    }
    public static  void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }

    //老韩说明
    //1. public synchronized void sell() {} 就是一个同步方法
    //2. 这时锁在 this对象
    //3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在this对象
    public  void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法

        synchronized (/*this*/ object) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }

            //休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));//1 - 0 - -1  - -2
        }
    }

    @Override
    public void run() {
        while (loop) {

            sell();//sell方法是一共同步方法
        }
    }
}

方法上加锁

class SellTicket01 extends Thread {
    private static int nums = 1000;
    private boolean loop=true;
    public synchronized void sell() {
        if (nums <= 0) {
            System.out.println("票卖完了");
            loop=false;
            return;
        }
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("售票口" + Thread.currentThread().getName() + "卖出一张票" + "剩余票数" + (nums--));
    }

    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }
}

互斥锁

基本介绍

1.Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。 2.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。 3.关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问 4.同步的局限性:导致程序的执行效率要降低 5.同步方法((非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象) 6.同步方法(静态的)的锁为当前类本身。

注意事项

1.同步方法如果没有使用static修饰:默认锁对象为this 2.如果方法使用static修饰,默认锁对象:当前类.class(static修饰没法用this) 3.实现的落地步骤: ·需要先分析上锁的代码 选择同步代码块或同步方法 要求多个线程的锁对象为同一个即可!

错误示范(锁对象不同)

Java线程(基础)

线程死锁

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

public class DeadLock_ {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLocKDEmo A = new DeadLockDemo(true);
        A.setName("A线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B线程");
        A.start();
        B.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() {

        //下面业务逻辑的分析
        //1. 如果flag 为 T, 线程A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
        //2. 如果线程A 得不到 o2 对象锁,就会Blocked
        //3. 如果flag 为 F, 线程B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
        //4. 如果线程B 得不到 o1 对象锁,就会Blocked
        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) { // 这里获得li对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入4");
                }
            }
        }
    }
}

释放锁和不释放锁情况

Java线程(基础)

Java线程(基础)

本章作业

Java线程(基础)

package Threaduse.HomeWork;

import java.util.Locale;
import java.util.Scanner;

//(1)在main方法中启动两个线程
//(2)第1个线程循环随机打印100以内的整数
//(3)直到第2个线程从键盘读取了“Q”命令。
public class Homework01 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        a.start();
        b.start();
    }
}
class A extends Thread {
    private  boolean loop=true;
    public  void setLoop(boolean b){
        loop=b;
    }
    @Override
    public void run() {
        //随机打印100以内的整数
        while(loop){
            System.out.println((int)(Math.random()*100+1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程A结束");
    }
}
class B extends Thread {
    private A a;
    Scanner scanner = new Scanner(System.in);
    public B(A a){
        this.a=a;
    }
    @Override
    public void run() {
        //接收键盘输入,当接受到"Q"后将loop=false;打断线程1
        while(true){
            char s=scanner.next().charAt(0);
            if(s=='Q') {
                a.setLoop(false);
                System.out.println("线程B结束");
              break;
            }
        }
    }
}

Java线程(基础)

package Threaduse.HomeWork;

public class Homework02 {
    public static void main(String[] args) {
        user user1 = new user();
        Thread thread1= new Thread(user1);
        Thread thread2 = new Thread(user1);
        thread1.setName("用户1");
        thread2.setName("用户2");
        thread1.start();
        thread2.start();

    }
}
class user implements Runnable{
    private  int money=10000;
    public void put(){
            while (true){
                synchronized (this) {
                    //不断从卡里取钱,每次取1000
                    if (money < 1000) {
                        System.out.println("卡里余额不足");
                        break;
                    }
                    money -= 1000;
                    System.out.println(Thread.currentThread().getName() + "正在取钱剩余余额" + (money));
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }
    @Override
    public void run() {
        put();
    }
}

脚本宝典总结

以上是脚本宝典为你收集整理的Java线程(基础)全部内容,希望文章能够帮你解决Java线程(基础)所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。