实现多线程方式一:继承Thread类
方法介绍
方法名 说明
void run() 在线程开启后,此方法将被调用执行
void start() 使此线程开始执行,Java虚拟机会调用run方法()
实现步骤
1. 定义一个类 MyThread 继承 Thread类
2. 在 MyThread类 中重写run()方法
3. 创建 MyThread类 的对象
4. 启动线程
代码演示
public class MyThread extends Thread {
@Override
public void run() {
// super.run();
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
package com.geekdatas;
/*
方式1: 继承Thread类
1、定义一个MyThread继承Thread类
2、在MyThread类中重写run()方法
3、创建MyThread类的对象
4、启动线程
*/
public class MyThreadDemo {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
// 还是单线程
// my1.run();
// my2.run();
//void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
my1.start();
my2.start();
}
}
设置和获取线程名称
方法介绍
方法名 说明
void setName(String name) 将此线程的名称更改为等于参数name
String getName() 返回此线程的名称
Thread currentThread() 返回对当前正在执行的线程对象的引用
代码演示
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
// String getName()返回此线程的名称
System.out.println(getName() + ":" + i);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.start();
my2.start();
}
}源码分析(通过无参构造方法创建线程对象的情况):
// 访问了父类的无参构造方法
public Thread() {
this((ThreadGroup)null, (Runnable)null, "Thread-" + nextThreadNum(),
0L);
}
---------------------------------------------------------
private static synchronized int nextThreadNum() {
return threadInitNumber++;// 0,1,......
}
private static int threadInitNumber;// 默认值从0开始
------------------------------------------------------------
// 无参构造方法,调用本类的其他构造方法
public Thread(ThreadGroup group, Runnable target, String name, long
stackSize) {
this(group, target, name, stackSize, (AccessControlContext)null,
true);
}
-------------------------------------------------------------
// 只看部分源代码
private Thread(ThreadGroup g, Runnable target, String name, long stackSize,
AccessControlContext acc, boolean inheritThreadLocals) {
......
if (name == null) {// name为空报异常
throw new NullPointerException("name cannot be null");
} else {
this.name = name;
......
}
}
通过 this.name = name; 发现有一个成员变量
private volatile String name;
---------------------------------------------------------
// getNmae里面就返回了成员变量this.name的值,所以我们输出的时候调用getNmae能得到
Thread-0,Thread-1......
public final String getName() {
return this.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);
}
}
}
/*
Thread类中获取和设置线程名称的方法:
void setName(String name):将此线程的名称更改为等于参数name
String getName():返回此线程的名称
Thread currentThread():返回对当前正在执行的线程对象的引用
*/
public class MyThreadDemo {
public static void main(String[] args) {
/*
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
// void setName(String name)将此线程的名称更改为等于参数name
my1.setName("高铁");
my2.setName("飞机");
*/
MyThread my1 = new MyThread("高铁");
MyThread my2 = new MyThread("飞机");
my1.start();
my2.start();
// Thread currentThread():返回对当前正在执行的线程对象的引用
System.out.println(Thread.currentThread().getName());
}
}
线程优先级
线程调度
两种调度方式
分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同, 那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
Java使用的是抢占式调度模型
随机性
假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得 到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随 机性,因为谁抢到CPU的使用权是不一定的
优先级相关方法
方法名 说明
final int
getPriority() 返回此线程的优先级
final void 更改此线程的优先级
setPriority(int 线程默认优先级是5;线程优先级的范围是:1~10
newPriority) 线程优先级高仅仅表示线程获取的CPU时间片的几率高,但是要 在次数比较多,或者多次运行的时候才能看到你想要的效果
代码演示
public class ThreadPriority extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ":" + i);
}
}
}
public class ThreadPriorityDemo {
public static void main(String[] args) {
ThreadPriority tp1 = new ThreadPriority();
ThreadPriority tp2 = new ThreadPriority();
ThreadPriority tp3 = new ThreadPriority();
tp1.setName("高铁");
tp2.setName("飞机");
tp3.setName("汽车");
//public final int getPriority():返回此线程的优先级
System.out.println(tp1.getPriority()); //5
System.out.println(tp2.getPriority()); //5
System.out.println(tp3.getPriority()); //5
//public final void setPriority(int newPriority):更改此线程的优先级
// tp1.setPriority(10000); //IllegalArgumentException
System.out.println(Thread.MAX_PRIORITY); //10
System.out.println(Thread.MIN_PRIORITY); //1
System.out.println(Thread.NORM_PRIORITY); //5
//设置正确的优先级
tp1.setPriority(5);
tp2.setPriority(10);
tp3.setPriority(1);
tp1.start();
tp2.start();
tp3.start();
}
}
线程控制
相关方法
方法名 说明
static void sleep(longmillis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join() 等待这个线程死亡(其他线程必须等待这个线程执行完毕才 有机会执行)
void setDaemon(booleanon) 将此线程标记为守护线程,当运行的线程都是守护线程时, Java虚拟机将退出
代码演示
sleep演示
package com.geekdatas;
public class ThreadSleep extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ":" + i);
}
}
}
---------------------------------------------------------------
package com.geekdatas;
/*
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒
数
*/
public class ThreadSleepDemo {
public static void main(String[] args) {
ThreadSleep ts1 = new ThreadSleep();
ThreadSleep ts2 = new ThreadSleep();
ThreadSleep ts3 = new ThreadSleep();
ts1.setName("曹操");
ts2.setName("刘备");
ts3.setName("孙权");
ts1.start();
ts2.start();
ts3.start();
}
}
-------------------------------------------------------
package com.geekdatas;
public class ThreadSleep extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ":" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
join演示
package com.geekdatas;
public class ThreadJoin extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ":" + i);
}
}
}
----------------------------------------------------------
package com.geekdatas;
/*
void join():等待这个线程死亡(其他线程必须等待这个线程执行完毕才有机会执行)
*/
public class ThreadJoinDemo {
public static void main(String[] args) {
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("康熙");
tj2.setName("四阿哥");
tj3.setName("八阿哥");
tj1.start();
try {
tj1.join();// 等待这个线程死亡,只有tj1执行完了以后,其他线程才有机会
执行
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}
Daemon演示
package com.geekdatas;
public class ThreadDaemon extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + ":" + i);
}
}
}
--------------------------------------------------------------------
package com.geekdatas;
/*
void setDaemon(boolean on):将此线程标记为守护线程,当运行的线程都是守护线程
时,Java虚拟机将退出
*/
public class ThreadDeamonDemo {
public static void main(String[] args) {
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setName("关羽");
td2.setName("张飞");
// 设置主线程为刘备
Thread.currentThread().setName("刘备");
// 设置守护线程 (主线程挂掉,其他线程也会挂掉,因为Java虚拟机将退出 注意:
其他不一定立即挂掉)
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" +
i);
}
}
}