Thread
1、多线程的实现方式1
方式一:继承Thread类
1、定义一个类MyThread继承Thread
2、在MyThread类中重写run()方法
3、创建MyThread类的对象
4、启动线程
注:void start() 导致此线程开始执行,java虚拟机调用此线程的run()方法
两个小问题:
1、 为什么要重写run()方法? 因为run()方法是用来封装被线程执行的代码
2、 run()与start()的区别?
区别1:run()封装线程执行的代码,直接调用,相当于普通方法
区别2:start()启动线程,然后由jvm调用此线程的run()方法
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for(int i = 0;i<100;i++){
System.out.println(i);
}
}
}
public class MyThreadDemo1 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
/* mt1.run();
mt2.run();*/
mt1.start();
mt2.start();
}
}
2、设置和获取线程名称
1. void setName(String name) 将此线程的名称更改为等于参数name
2. String getName() 返回此线程的名称
public class MyThread extends Thread {
//无参构造
public MyThread() {
}
//带参构造
public MyThread(String name) {
super(name);
}
@Override
public void run() {
super.run();
for(int i = 0;i<100;i++){
System.out.println(getName()+":"+i);//获取线程名称
}
}
}
public class MyThreadDemo1 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
/* mt1.run();
mt2.run();*/
mt1.setName("beijing");//设置线程名称
mt2.setName("shanghai");//无参构造赋值
MyThread mt3 = new MyThread("hangzhou");//调用带参构造方法
MyThread mt4 = new MyThread("xian");
mt1.start();
mt2.start();
mt3.start();
mt4.start();
//获取main()方法线对象名称
System.out.println(Thread.currentThread().getName());
}
}
3、线程调度
线程调度有2种调度模型:
1. 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
2. 抢占式调度模型:优秀让优先级高的线程使用CPU,如果线程的优先级相同,那么随机选择一个,优先级高的线程获取的CPU时间片相对多一些
注:Java使用的是抢占式调度模型
Thread类中设置和获取线程优先级的2个方法:
1. Public final int getPriority() 返回线程的优先级
2. Public final void setPriority(int newPriority) 更改此线程的优先级
优先级范围:
1. 线程优先级的默认值:5
2. MIN_PRIORITY: 线程优先级的最小值1
3.MAX_PRIORITY: 线程优先级的最大值10
public class ThreadPriority extends Thread{
@Override
public void run() {
super.run();
for(int i = 0;i<100;i++){
System.out.println(getName()+":"+i);//获取线程名称
}
}
}
public class ThreadPriorityDemo1{
public static void main(String[] args) {
ThreadPriority tp1 = new ThreadPriority();
ThreadPriority tp2 = new ThreadPriority();
ThreadPriority tp3 = new ThreadPriority();
tp1.setName("beijing");
tp2.setName("hangzhou");
tp3.setName("shengzhen");
System.out.println(tp1.getPriority());
System.out.println(tp2.getPriority());
System.out.println(tp3.getPriority());
tp3.setPriority(1); // 设置线程优先级
tp1.start();
tp2.start();
tp3.start();
}
}
4、线程控制
常用三种方式:
1、 static void sleep(long milis) : 使用当前正在执行的线程停留(暂停执行)指定毫秒
2、 Void join() : 等待这个线程死亡
3、 Void setDaemon(boolean on) : 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机退出
//案例一
public class ThreadSleep extends Thread {
@Override
public void run() {
super.run();
for(int i = 0;i<100;i++){
System.out.println(getName()+":"+i);//获取线程名称
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//static void sleep(long milis) : 使用当前正在执行的线程停留(暂停执行)指定毫秒
public class ThreadSleepDemo {
public static void main(String[] args) {
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep();
ts1.setName("beijing");
ts2.setName("hangzhou");
ts3.setName("shengzhen");
ts1.start();
ts2.start();
ts3.start();
}
//案例二
public class ThreadJoin extends Thread{
@Override
public void run() {
super.run();
for(int i = 0;i<100;i++){
System.out.println(getName()+":"+i);//获取线程名称
}
}
}
//Void join() : 等待这个线程死亡
public class ThreadJoinDemo {
public static void main(String[] args) throws InterruptedException {
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("beijing");
tj2.setName("hangzhou");
tj3.setName("shengzhen");
tj1.start();
tj1.join(); //等调用的线程完毕后,其它线程才能执行
tj2.start();
tj3.start();
}
}
//案例三
public class ThreadDaemon extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 100; i++) {
System.out.println(getName()+":"+i);
}
}
}
//Void setDaemon(boolean on) : 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机退出
public class ThreadDaemonDemo {
public static void main(String[] args) {
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
ThreadDaemon td3 = new ThreadDaemon();
td1.setName("beijing");
td2.setName("shengzhen");
//设置主线程为hangzhou
Thread.currentThread().setName("hangzhou");
//设置守护线程,就是主线程结束后,守护线程不再执行下去
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
5、线程生命周期
6、多线程的实现方式2
方式二:实现Runnable接口
1. 定义一个类MyRunnable实现Runnable接口
2. 在MyRunnable中重写run()方法
3. 创建MyRunnable类的对象
4. 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
5. 启动线程
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//实现的Runnable接口,就必须要当拿到当前线程,再去获取名字,
//这里不能直接使用getName()
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class MyRunnableDemo1 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
//把MyRunnable的构造方法对象作为参数,创建2个线程
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//实现Runnable接口给线程取名字
Thread t3 = new Thread(mr,"beijing");
Thread t4 = new Thread(mr,"hangzhou");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
实现Runnable接口方式的优点:
1、 避免java单继承的局限性
2、 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想