java线程的创建和启动


文章目录

  • 多线程
  • 线程的状态
  • 线程调度
  • 线程优先级
  • 线程休眠
  • 阻塞线程
  • 线程礼让
  • 线程调度练习


多线程

线程的状态

java线程状态和线程调度_java

package Threads;

public class MyThread5 implements Runnable {
    @Override
    public void run() {
        System.out.println("线程正在运行,处于运行状态");
        try {
            System.out.println("线程开始休眠,处于阻塞状态");
            //线程休眠5S
            Thread.sleep(5000);
            System.out.println("线程休眠结束,阻塞状态结束,再次进入就绪状态");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("线程中断");
        }
    }
}
package Test;

import Threads.MyThread5;

//测试线程的状态
public class MyThread5Test {
    public static void main(String[] args) {
        Runnable runnable = new MyThread5();
        Thread t = new Thread(runnable);
        System.out.println("线程处于创建状态");
        t.start();
        System.out.println("线程处于就绪状态");
    }
}

线程调度

线程优先级

由于线程之间的运行是通过抢占CPU的资源来进行的,线程调度指的是按照特定的机制为多个线程分配CPU的使用权。

java线程状态和线程调度_优先级_02

线程的优先级由1-10表示,1表示最低,10最高,默认的优先级是5。优先级高的线程获得CPU的资源概率比较大.

尝试更改线程的优先级:

package Threads;

//创建线程类,实现Runnable接口
public class MyThread2 implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
package Test;

import Threads.MyThread2;

//测试线程
public class MyThread2Test {
    public static void main(String[] args) {
        //创建线程对象
        Runnable runnable = new MyThread2();
        Thread thread = new Thread(runnable, "mythread1");
        Thread thread1 = new Thread(runnable, "mythread2");
        //线程调度,设置线程优先级
//        thread1.setPriority(10);
//        thread.setPriority(1);
        thread1.setPriority(Thread.MAX_PRIORITY);
        thread.setPriority(Thread.MIN_PRIORITY);
        //启动线程
        thread.start();
        thread1.start();
    }
}
线程休眠

线程调度的另一个方案是线程休眠。让线程展示睡眠指定的时长,线程会进入到阻塞状态,睡眠时间过后的线程会再进入可运行的状态。

方法是:

public static void sleep(long millis)

millis是休眠时长,以毫秒为单位,调用sleep()方法需要处理InterruptedException异常。

package Threads;

//模拟线程休眠的过程
public class Wait {
    public static void bySec(long s) {
        for (int i = 1; i <= 5; i++) {
            System.out.println(i+"秒");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        System.out.println("线程开始休眠");
        Wait.bySec(5);
        System.out.println("线程结束休眠");
    }
}
阻塞线程
  • join()方法
    等待该线程终止,等待加入的其他线程结束后在继续执行本线程
package Threads;

public class MyThread6 implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 30; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
package Test;


import Threads.MyThread6;

public class MyThread6Test {
    public static void main(String[] args) {
        //创建子线程对象t
        Runnable runnable = new MyThread6();
        Thread t = new Thread(runnable, "myThread");
        t.start();
        //主线程main做的事情
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            //当i = 5的时候,强制把t线程加入执行
            //线程调度:join()--等待线程终止,等待t线程执行结束后,main主线程再继续执行
            if (i == 5) {
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
线程礼让
  • yield()方法

暂停当前线程,允许其他具有相同优先级的线程获得运行机会,该线程处于就绪状态,不会转为阻塞状态。这是线程之间的礼让问题,只是提供一种可能,但是不能保证一定会礼让成功。

package Threads;

public class MyThread7 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <= 4; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            if (i == 3) {
                Thread.yield();
            }
        }
    }
}
package Test;


import Threads.MyThread7;

public class MyThread7Test {
    public static void main(String[] args) {
        Runnable runnable = new MyThread7();
        Thread t1 = new Thread(runnable, "线程A");
        Thread t2 = new Thread(runnable, "线程B");
        t1.start();
        t2.start();
    }
}
线程调度练习
  • 优先级问题
package Threads;

public class MyThread8 implements Runnable {
    @Override
    public void run() {

    }
}
package Test;

import Threads.MyThread8;

//获取和设置主线程和子线程的优先级
public class MyThread8Test {
    public static void main(String[] args) {
        //主线程
        Thread mainThread = Thread.currentThread();
        //子线程
        Thread myThread = new Thread(new MyThread8());
        System.out.println("默认的优先级");
        System.out.println("主线程名:" + mainThread.getName() + "优先级:" + mainThread.getPriority());
        System.out.println("子线程名:" + myThread.getName() + "优先级:" + myThread.getPriority());
        System.out.println("修改优先级后");
        mainThread.setPriority(Thread.MAX_PRIORITY);
        myThread.setPriority(Thread.MIN_PRIORITY);
        System.out.println("主线程名:" + mainThread.getName() + "优先级:" + mainThread.getPriority());
        System.out.println("子线程名:" + myThread.getName() + "优先级:" + myThread.getPriority());
    }
}
  • 练习
    需求:某一个科室一天需看普通号20个,特需号10个,特需号的看病时间是普通号的2倍。开始时普通号和特需号并行叫号,叫到特需号的概率比普通号的高。当普通号叫完第10号时,要求先看完全部的特需号再看普通号。
package Threads;

public class SpecialThread implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println("特需号:" + i + "号病人正在看病");
            //线程休眠来表示看病的过程
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package Threads;

//模拟医院看病
public class CommonThread {
    public static void main(String[] args) {
        //当前线程--普通号
        //创建一个特需号的线程
        Thread special = new Thread(new SpecialThread());
        special.setPriority(Thread.MAX_PRIORITY);
        special.start();
        for (int i = 1; i <= 20; i++) {
            System.out.println("普通号:" + i + "号病人在看病");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 10) {
                try {
                    special.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 多线程数据共享问题

多个线程共享数据时,可能会引发数据的不安全问题。

package Threads;

public class TicketThread implements Runnable {
    private int ticket = 10;//记录车票总数
    private int num = 0;//记录用户抢到了第几张票

    //用户抢票
    @Override
    public void run() {
        while (true) {
            if (ticket <= 0) {
                break;
            }
            //有余票,则抢票
            //修改车票数:总票数在抢完票后减一张
            ticket--;
            //用户抢完票后,票数加一
            num++;
            //模拟网络延迟
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //显示出票反馈给用户
            System.out.println(Thread.currentThread().getName() + "抢到了第" + num + "张票,剩余" + ticket + "张票");
        }
    }
}
package Test;

import Threads.TicketThread;

public class TicketThreadTest {
    public static void main(String[] args) {
        Runnable runnable = new TicketThread();
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        System.out.println("各方开始抢票");
        t1.start();
        t2.start();
        t3.start();
    }
}

java线程同步