多线程
三种实现方式:
- 继承Thread类
- 实现Runnable接口
- 利用Callable和Futrue接口
继承Tread类实现多线程:
- 定义一个MyThread类继承Thread类
- 在MyThread类中重写run()
- 创建MyThread类的对象
- 启动线程
public class MyThread extends Thread{
@Override
public void run() {
//代码就是线程开启后执行的代码
for (int i = 0; i <100 ; i++) {
System.out.println("线程开启了"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread t1= new MyThread();
MyThread t2= new MyThread();
t1.start();
t2.start();
}
}
为什么重写run()?
run()是用来封装被线程执行的代码
run()和start()有什么区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。
start():启动线程;然后由JVM调用此线程的run()方法。
通过Runnable接口实现多线程:
- 定义一个类MyRunnable实现Runnable接口
- 在MyRunnable类中重写run()方法
- 创建MyRunnable类的对象
- 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
- 启动线程
public class MyRunnable implements Runnable {
@Override
public void run() {
//线程启动后执行的代码
for (int i = 0; i < 100; i++) {
System.out.println("第二种方式实现多线程" + i);
}
}
}
public class Demo {
public static void main(String[] args) {
//创建了一个参数对象
MyRunnable mr = new MyRunnable();
//创建了一个线程对象,并把参数传递给这个线程
//在线程启动后,执行的就是参数里的run()方法
Thread t1=new Thread(mr);
//开启线程
t1.start();
MyRunnable mr2 = new MyRunnable();
Thread t2 = new Thread(mr2);
t2.start();
}
}
通过Callable和Future实现多线程:
- 定义一个MyCallable类实现Callable接口
- 在MyCallable类中重写call()方法
- 创建MyCallable类的对象
- 创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
- 创建Thread类的对象,把FutureTask对象作为构造方法的参数
- 启动线程
- 调用get()方法获取线程之后的结果
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("跟女孩表白的次数"+i);
}
//返回值表示线程运行完毕后的结果
return "答应";
}
}
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程开启后需要执行call方法
MyCallable mc = new MyCallable();
//可以获取线程执行完毕后的结果,也可以作为参数传递给Thread对象
FutureTask<String> future = new FutureTask(mc);
//创建线程对象
Thread t1=new Thread(future);
t1.start();
//获得线程运行后的结果,如果线程没有结束,get方法会一直死等
String s = future.get();
System.out.println(s);
}
}s
| 三种方式对比 | 优点 | 缺点 |
| 实现Runnable、Callable接口 | 扩展性强,实现该接口的同时还可以继承其他的类。 | 编程相对复杂,不能直接使用Thread类中的方法。 |
| 继承Thread类 | 变成比较简单,可以直接使用Thread类中的方法。 | 可以扩展性较差,不能再继承其他的类。 |
Thread类中常用方法
获取和设置线程的名称
获取线程名字
String getName():返回此线程的名称。
设置线程名字
void setName(String name):将此线程的名称更改为等于参数name。
通过构造方法也可以设置线程名称。
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@@@"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
//线程是有默认的名字的,格式:Thread-数字
MyThread t1 = new MyThread("小菜");
MyThread t2 = new MyThread();
//t1.setName("小菜");
t2.setName("小果");
t1.start();
t2.start();
}
}
获得当前线程的对象
public static Thread cureentThread():返回当前正在执行的线程对象的引用
public class MyRunnable implements Runnable {
@Override
public void run() {
//线程启动后执行的代码
for (int i = 0; i < 100; i++) {
//获取当前线程的名字
System.out.println(Thread.currentThread().getName()+"第二种方式实现多线程" + i);
}
}
}
线程休眠
public static void sleep(long time):让线程休眠指定的时间,单位为毫秒。
public class Demo {
public static void main(String[] args) throws InterruptedException {
System.out.println("睡觉前");
Thread.sleep(10000);
System.out.println("睡醒了");
}
}
线程调度
多线程的并发运行:计算机的CPU在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行代码。
各个线程轮流获得CPU的使用权,分别执行各自的任务。
线程有两种调度模型:
分时调度模型:所有线程轮流使用CPU,平均分配每个线程占用CPU的时间片。
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。
线程的优先级:
public final void setPriority(int newPriority):设置线程的优先级
public final int getPriority(): 获取线程的优先级
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
return "success!";
}
}
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程优先级1-10,默认为5
MyCallable mc1 = new MyCallable();
MyCallable mc2 = new MyCallable();
FutureTask<String> ft1 = new FutureTask(mc1);
FutureTask<String> ft2 = new FutureTask(mc2);
Thread t1 = new Thread(ft1);
Thread t2 = new Thread(ft2);
t1.setName("飞机");
t2.setPriority(8);
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
t2.setName("坦克");
t1.start();
t2.start();
String s = ft1.get();
System.out.println(s);
}
}
后台线程、守护线程
public final void setDaemon(boolean on):设置守护线程。
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "-----" + i);
}
}
}
public class MyThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "-----" + i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread1 thread1 = new MyThread1();
MyThread2 thread2 = new MyThread2();
thread1.setName("男神");
thread2.setName("备胎");
//thread2设置成守护线程
//但普通线程执行完毕后,守护线程也没有运行下去的必要了(不会立马停止)
thread2.setDaemon(true);
thread1.start();
thread2.start();
}
}

浙公网安备 33010602011771号