Java多线程

一、线程的创建

 创建一个Thread类,或者一个Thread子类的对象

 创建一个实现Runnable接口的类的对象

Thread类

 构造方法:

  Thread();创建一个线程对象

  Thread(String name);创建一个具有指定名称的线程对象

  Thread(Runnable target);创建一个基于Runnable接口实现类的线程对象

  Thread(Runnable target,String name);创建一个基于Runnable接口实现类,并且具有指定名称的线程对象

 常用方法:

  void run();线程相关的代码写在该方法中,一般需要重写

  void start();启动线程

  static void sleep(long m);线程休眠m毫秒

  void join();优先执行调用join方法的线程

Runnable接口

 只有一个方法run();

 Runnable是Java中用以实现线程的接口

 任何实现线程功能的类都必须实现该接口

案例1:通过继承Thread类创建线程

public class MyThread extends Thread{
    public void run(){
        System.out.println(getName()+"该线程正在执行!");
    }
}
复制代码
public class ThreadTest {
    public static void main(String[] args) {
        //线程何时获得cpu的使用权是随机的
        System.out.println("主线程1");
        MyThread myThread=new MyThread();
        myThread.start();//启动线程,start()方法只能被调用一次
        System.out.println("主线程2");

    }
}
复制代码

案例2:实现Runnable接口创建线程

 为什么要实现Runnable接口?

  - Java不支持多继承

  - 不打算重写Thread类的其他方法

复制代码
class PrintRunnable implements Runnable{
    int i=1;
    @Override
    //run()方法中的代码可以被多个线程共享,
    public void run() {
        while(i<=10)
            System.out.println(Thread.currentThread().getName()+"正在运行第"+(i++)+"次");
    }
}
public class Test {
    public static void main(String[] args) {
        //多个线程处理同一个资源
        PrintRunnable pr=new PrintRunnable();
        Thread t1=new Thread(pr);
        t1.start();
        
        Thread t2=new Thread(pr);
        t2.start();
    }
}
复制代码

 

二、线程的状态和生命周期

 线程的5个状态

  - 新建(New)

  - 可运行(Runnable)

  - 正在运行(Running)

  - 阻塞(Blocked)

  - 终止(Dead)

 

 

 

sleep方法的应用

  puble static void sleep(long milles)

 作用:在指定的毫秒数内让正在执行的线程休眠(暂停执行)

 参数为休眠时间,单位是毫秒

复制代码
public class Letter implements Runnable{
    char letter[]=new char[26];
    public Letter(){
        for(int i=0;i<26;i++){
            letter[i]=(char)(97+i);
        }
    }
    @Override
    public void run() {
        for(int i=0;i<26;i++){
            System.out.print(letter[i]);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Test{
    public static void main(String[] args) {
        Letter letter=new Letter();
        Thread t=new Thread(letter);
        t.start();
    }
}
复制代码

join方法的应用

  public final void join()

 作用:等待调用该方法的线程结束后才能执行

  public final void join(long millis)

 作用:等待该线程终止的时间最长为millis毫秒

复制代码
class MyThread1 extends Thread{
    public void run(){
        for(int i=1;i<=500;i++)
            System.out.println(getName()+"正在执行第"+i+"次");
    }
}
public class JoinDemo {
    public static void main(String[] args) {
        MyThread1 mt=new MyThread1();
        mt.start();
        try {
            mt.join(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=1;i<=3;i++)
            System.out.println("主线程运行第"+i+"次");
        System.out.println("主线程运行结束");
    }
}
复制代码

 

线程优先级

 - Java为线程类提供了10个优先级,数字越大优先级越高

 - 优先级可以用整数1-10表示,超出范围会抛出异常

 - 主线程默认优先级为5

 - 也可以用优先级常量表示线程的优先级

  MAX_PRIORITY:线程的最高优先级10

  MIN_PRIORITY:线程的最小优先级1

  NORM_PRIORITY:线程的默认优先级5

 优先级相关的方法:

  public int getPrority() 获取线程优先级

  public void setPrority() 设置线程优先级

三、线程同步

 多线程运行问题:

  1.各个线程通过竞争cpu时间而获得运行机会的

  2.各线程什么时候得到cpu时间,占用多久,是不可预测的

  3.一个正在运行的线程在什么地方被暂停是不确定的

 

同步

 synchronized关键字用在

  - 成员方法

  - 静态方法

  - 语句块

 可以确保共享对象在同一时刻只能被一个线程访问

  public synchronized void saveAccount(){}

  public static synchronized void saveAccount(){}

  synchronized(obj){……}

 由于线程运行的随机性,可能会出现数据丢失的问题:

复制代码
public class Bank {
    private String account;//账号
    private int balance;//账户余额
    public Bank(String account, int balance) {
        this.account = account;
        this.balance = balance;
    }
    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Bank[账号:"+ account + ", 余额:" + balance + "]";
    }
    //存款
    public void saveAccount(){
        //可以在不同的位置处添加sleep方法
            //获取当前的账号余额
            int balance=getBalance();
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            //修改余额,存100元
            balance+=100;
            //修改账户余额
            setBalance(balance);
            //输出存款后的账户余额
            System.out.println("存款后的账户余额为:"+balance);
    }
    //取款
    public void drawAccount(){
        //获取当前的账户余额
        int balance=getBalance();
        //修改金额,取200
        balance=balance-200;
        try{
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        //修改账户余额
        setBalance(balance);
        System.out.println("取款后的账户余额:"+balance);
    }
}
Bank
复制代码
复制代码
//取款
public class DrawAccount implements Runnable{
    Bank bank;
    public DrawAccount(Bank bank){
        this.bank=bank;
    }
    @Override
    public void run() {
        bank.drawAccount();
    }
}
DrawAccount
复制代码
复制代码
//存款
public class SaveAccount implements Runnable{
    Bank bank;
    public SaveAccount(Bank bank){
        this.bank=bank;
    }
    @Override
    public void run() {
        bank.saveAccount();
    }
}
SaveAccount
复制代码
复制代码
//测试
public class Test {
    public static void main(String[] args) {
        //创建账户,给定金额1000
        Bank bank=new Bank("1001",1000);
        //创建线程对象
        SaveAccount sa=new SaveAccount(bank);
        DrawAccount da=new DrawAccount(bank);
        Thread save=new Thread(sa);
        Thread draw=new Thread(da);
        save.start();
        draw.start();
        try {
            save.join();
            draw.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(bank);
    }
}
Test
复制代码

 

 使用synchronized关键字对Bank对象进行锁定后可解决执行被打断这一问题

案例3:synchronized的应用

复制代码
//存款
    public synchronized void saveAccount(){
        //获取当前的账号余额
        int balance=getBalance();
        try{
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        //修改余额,存100元
        balance+=100;
        //修改账户余额
        setBalance(balance);
        //输出存款后的账户余额
        System.out.println("存款后的账户余额为:"+balance);
    }
    //取款
    public void drawAccount(){
        synchronized (this){
            //获取当前的账户余额
            int balance=getBalance();
            //修改金额,取200
            balance=balance-200;
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            //修改账户余额
            setBalance(balance);
            System.out.println("取款后的账户余额:"+balance);
        }

    }
Bank的修改部分
复制代码

 

 四、线程间通信

 wait()方法:中断方法的执行,使线程等待

 notify()方法:唤醒处于等待的某一个线程,使其结束等待

 notifyAll()方法:唤醒所有处于等待的线程,使它们结束等待

 案例4:天气生产与读取

复制代码
public class Weather {
    private int tempeature;
    private int humidity;
    private boolean flag=false;

    public int getTempeature() {
        return tempeature;
    }
    public void setTempeature(int tempeature) {
        this.tempeature = tempeature;
    }
    public int getHumidity() {
        return humidity;
    }
    public void setHumidity(int humidity) {
        this.humidity = humidity;
    }

    public synchronized void generate(){
        if(flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int t=(int)(Math.random() *40);
        int h=(int)(Math.random() *100);
        setTempeature(t);
        setHumidity(h);

        System.out.println("生成天气数据[温度:"+t+",湿度:"+h+"]");
        flag=true;
        notifyAll();
    }

    public synchronized void read(){
        if(!flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int t=getTempeature();
        int h=getHumidity();
        System.out.println("读取天气数据[温度:"+t+",湿度:"+h+"]");
        flag=false;
        notifyAll();
    }
}
Weather
复制代码
复制代码
public class GenerateWeather implements Runnable{
    Weather weather;
    public GenerateWeather(Weather weather){
        this.weather=weather;
    }
    @Override
    public void run() {
        while(true){
            weather.generate();
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
GenerateWeather
复制代码
复制代码
public class ReadWeather implements Runnable{
    Weather weather;
    public ReadWeather(Weather weather){
        this.weather=weather;
    }
    @Override
    public void run() {
        while(true){
            weather.read();
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
ReadWeather
复制代码
复制代码
public class Test {
    public static void main(String[] args) {
        Weather weather=new Weather();
        new Thread(new GenerateWeather(weather)).start();
        new Thread(new ReadWeather(weather)).start();
    }
}
Test
复制代码

 

posted @   南风知君  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示