1. 线程是什么
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
一个进程可以有很多个线程,每条线程并行执行不同的任务。
同一进程中的多条线程将共享该进程中的全部系统资源。
2. 线程创建
2.1 继承 Thread 类
Thread 的特点:
1. 继承 2. 不灵活 3. 数据不共享
启动线程的唯一办法是 调用 start() 方法
实现步骤:
1. 创建一个实现类
2. 在创建一个类,继承 Thread
3. 在继承了 Thread 类中,重写 run() 方法
4. 在通过实体类对象调用 start() 方法 实现
例:
鼠鼠写的是一个售票
public class MyThread1 extends Thread{
private int tickect = 5;
@Override
public void run(){
while (tickect>0){
System.out.println(Thread.currentThread().getName()+"卖出去了一张票,还剩"+tickect--);
}
}
}
调用 start() 方法
public class MyTest {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
myThread1.setName("ndt");
myThread1.start();
MyThread1 myThread2 = new MyThread1();
myThread2.setName("test");
myThread2.start();
}
}
上述代码执行后的效果:
以下为查阅(鼠鼠也有不理解滴):
run() : 表示此线程中要干什么事
start() : 调用完 start() 方法后,线程不一定立即执行,有CPU调度,调度完后,会执行线程中的 run() 方法
问题?
如果我不调用 start() 方法,直接调用 run() 方法,会有什么结果?
答: 如程序依旧可以运行,只不过是没有创建出一个新的线程,就只有一个 main 线程在运行,但依旧会运行 run() 方法
2.2 实现 Runnable 接口
Runnable 的特点:
1. 实现接口 2. 灵活 3. 数据共享
实现步骤:
1. 创建一个实现类
2. 在创建一个类,实现 Runnable 接口
3. 在实现 Runnable 接口中,重写 run() 方法
4. 在通过实体类对象调用 start() 方法 实现
例:
还是售票
public class MyTest2 {
public static void main(String[] args) {
MyThread2 myThread1 = new MyThread2();
Thread thread = new Thread(myThread1,"test1");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
Thread thread2 = new Thread(myThread1,"test2");
thread2.setPriority(Thread.MAX_PRIORITY);
thread2.start();
}
}
public class MyThread2 implements Runnable{
private int tickect=5;
@Override
public void run(){
while (tickect>0){
System.out.println(Thread.currentThread().getName()+"卖出去了一张票,还剩"+tickect--);
}
}
}
上述代码执行后的效果:
2.3 实现 Callable 接口
Callable 的特点:
1. 实现数据共享 2. 有返回值 3. 可以抛出异常
实现步骤:
1. 创建一个类
2. 实现 Callable 接口
3. 在实现 Callable 接口中,重写 call() 方法
4. 启动线程:
创建线程实例
FutureTask
Thread
start() -> run() -> FutureTask call
例:
还是售票
public class MyThread3 implements Callable {
private int tickect = 5;
@Override
public Object call() throws Exception{
while (tickect>0){
System.out.println(Thread.currentThread().getName()+"卖出去了一张票,还剩"+tickect--);
}
return "ok";
}
}
public class MyTest3 {
public static void main(String[] args) {
MyThread3 myThread3 = new MyThread3();
FutureTask<String> futureTask =new FutureTask<>(myThread3);
FutureTask<String> futureTask2 =new FutureTask<>(myThread3);
Thread thread = new Thread(futureTask,"yyl1");
Thread thread2 = new Thread(futureTask2,"yyl2");
thread.start();
thread2.start();
String s = null;
try {
s=futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(s);
}
}
上述代码执行后的效果:
3. 线程常用的方法
3.1 sleep 方法
sleep() 方法: 它是Thread类的静态方法 用来让当前线程休眠指定时间
例:
public class MyThreadZhongduan extends Thread{
// 重写 run方法
private int tickect = 5;
// 重写 run方法
@Override
public void run() {
//
while (tickect > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 查看当前的休眠的状态
System.out.println("中断:" + Thread.currentThread().isInterrupted());
// 票减1
System.out.println(Thread.currentThread().getName() + "卖出去了一张票,还剩:" + tickect--);
}
}
}
public class MyTestZhongduan {
// 多个线程同时启动
public static void main(String[] args) {
//
MyThreadZhongduan myThread1 = new MyThreadZhongduan();
myThread1.setName("ndt");
MyThreadZhongduan myThread2 = new MyThreadZhongduan();
myThread2.setName("test");
// 第一个线程
myThread1.start();
myThread1.interrupt();//
// 第一个线程
myThread2.start();
}
}
上述代码执行后的效果:
3.2 join 方法
join() 方法: 当前的线程执行完其他的线程才能够执行
例:
public class MyThread1 extends Thread {
// 重写 run方法
private int tickect = 5;
// 重写 run方法
@Override
public void run() {
//
while (tickect > 0) {
// 票减1
System.out.println(Thread.currentThread().getName() + "卖出去了一张票,还剩:" + tickect--);
}
}
}
public class MyTest {
// 多个线程同时启动
public static void main(String[] args) {
//
MyThread1 myThread1 = new MyThread1();
myThread1.setName("ndt");
// 第一个线程
myThread1.start();
try {
myThread1.join();// ndt
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
MyThread1 myThread2 = new MyThread1();
myThread2.setName("test");
// 第一个线程
myThread2.start();
}
}
上述代码执行后的效果:
3.3 yield 方法
yield() 方法: 礼让线程。让当前正在执行的线程暂停,但不阻塞(将线程从运行状态转换为就绪状态),但不一定成功,完全取决于 CPU。简单来说,就是让 CPU 重新调度线程
例:
public class MyThreadLirang implements Runnable {
private int tickect = 5;
// 重写 run方法
@Override
public void run() {
//
while (tickect > 0) {
String name = Thread.currentThread().getName();
if (name.equals("test1")) {
Thread.yield();
}
// 票减1
System.out.println(name + "卖出去了一张票,还剩:" + tickect--);
}
}
}
public class MyTestLiRang {
// 多个线程同时启动
public static void main(String[] args) {
MyThreadLirang myThread1 = new MyThreadLirang();
Thread thread = new Thread(myThread1,"test1");
Thread thread2 = new Thread(myThread1,"test2");
thread.start();
thread2.start();
}
}
上述代码执行后的效果:
不管执行多少次 test1 会一直比 test2 多卖