多线程
线程的状态
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的使用权。
线程的优先级由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();
}
}