什么是线程与进程
进程:类似于电脑打开的QQ、酷我音乐、腾讯影视等软件
线程:在看电视的时候听歌并且聊天都属于线程完成的
并发与并行
并发:单位时间内可以执行的请求次数
并行:在某一时刻可以执行的请求次数
多线程实现的三种方式
- 继承Thread类,重写run方法
- 实现Runable接口,重写run方法
- 实现Callable接口,重写call方法
实现方式1
package ms.studyjava.threads.demo1;
import lombok.SneakyThrows;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* 创建线程的三种方式
*
* **/
public class NewThread {
public static void main(String[] args) throws Exception {
NewThread newThread = new NewThread();
newThread.getThread();
newThread.getRunable();
newThread.getFuture();
}
public void getThread(){
ThreadMethods threadMethods = new ThreadMethods();
threadMethods.setName("Thread线程名称");
threadMethods.start();
}
public void getRunable(){
RunableMethods runableMethods = new RunableMethods();
//创建Thread对象。对象调用start启动线程
Thread thread = new Thread(runableMethods,"runable线程名称");
thread.start();
}
public void getFuture() throws ExecutionException, InterruptedException {
CallableMethods callableMethods = new CallableMethods();
//将实现Callable接口的类的对象,丢进FutureTask构造方法中得到新的FutureTask对象,在创建Thread对象调用satrt方法启动线程
FutureTask<String> stringFutureTask = new FutureTask<>(callableMethods);
Thread thread = new Thread(stringFutureTask,"callabel线程名称");
thread.start();
//等待线程结束进行返回值接受
while (true){
if (stringFutureTask.isDone()){
System.out.println(stringFutureTask.get());
break;
}
}
}
}
/**
*
* 继承Thread,重写Run方法
* **/
class ThreadMethods extends Thread{
@SneakyThrows
@Override
public void run() {
System.out.println("-----------Thrad-------------");
System.out.println(Thread.currentThread().getName());
System.out.println("----------Thrad--------------");
}
}
/**
* * 实现Runable接口,重写Run方法
* **/
class RunableMethods implements Runnable{
@Override
public void run() {
System.out.println("----------Runable--------------");
System.out.println(Thread.currentThread().getName());
System.out.println("----------Runable--------------");
}
}
/**
* * 实现Callable接口重写call接口
* **/
class CallableMethods implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("----------Callable--------------");
System.out.println(Thread.currentThread().getName());
System.out.println("----------Callable--------------");
return "调用callable返回的值";
}
}
实现方式2
package com.ms.study.demo.thread;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @ClassName: RunableThread
* @Description:
*/
public class CreateThread {
public void createthread(){
new Thread(){
@Override
public void run() {
System.out.println("启动Thread线程");
}
}.start();
}
public void createRubale(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("启动Runable线程");
}
};
new Thread(runnable).start();
}
public Object createCallable() throws ExecutionException, InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() {
System.out.println("启动callable线程");
return "callable线程返回值";
}
};
FutureTask<String> taskFuture = new FutureTask<String>(callable);
new Thread(taskFuture).start();
return taskFuture.get();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CreateThread runableThread = new CreateThread();
runableThread.createthread();
runableThread.createRubale();
Object callable = runableThread.createCallable();
System.out.println(callable);
}
}
可以轻易的发现,不管你用那种方式实现线程,最终都是需要通过new Thread().statr()方法进行线程启动
怎么让线程安全停止
- 安全执行结束
- 抛出异常
- interrupt线程中断。来源于Thread里面一个方法,用于中断线程。该方法相当于给当前线程一个提示,提示该线程需要进行中断,至于是否一定中断,完全取决于该线程自己
使用interrupt中断线程
1.正常的中断线程
class ThreadStopMethods extends Thread {
@Override
public void run() {
//判断当前线程是否被中断,没有中断就继续执行业务。返回true表示已中断
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + "未被中断,正在执行业务.....");
}
//线程已经被中断时候打印
System.out.println(Thread.currentThread().getName() + "中断状态:" + Thread.currentThread().isInterrupted());
}
}
/**
* 线程安全停止的方法
*/
public void safeStop() throws InterruptedException {
ThreadStopMethods thread = new ThreadStopMethods();
//1.interrupt。来源于Thread里面一个方法,用于中断线程
//该方法相当于给当前线程一个提示,提示该线程需要进行中断,至于是否一定中断,完全取决于该线程自己
thread.setName("interrupt中断线程---");
thread.start();
//让主线程睡眠一段时间
Thread.sleep(3000);
//中断线程
thread.interrupt();
}
interrupt中断线程---未被中断,正在执行业务.....
interrupt中断线程---未被中断,正在执行业务.....
interrupt中断线程---未被中断,正在执行业务.....
interrupt中断线程---未被中断,正在执行业务.....
interrupt中断线程---中断状态:true
2.抛出InterruptedException 异常情况,线程中断的标志会一直被复位成false。需要自己在线程的try-catch中手动的中断
会发现一旦抛出InterruptedException异常后,中断状态将一直都是复位成false的,也就是说一直无限循环执行下去
class ThreadStopMethods extends Thread {
@Override
public void run() {
//判断当前线程是否被中断,没有中断就继续执行业务。返回true表示已中断
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"--抛出InterruptedException异常,中断状态:"+Thread.currentThread().isInterrupted());
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
System.out.println(Thread.currentThread().getName() + "已被中断,中断状态:" + Thread.currentThread().isInterrupted());
}
}
interrupt中断线程---
interrupt中断线程---
interrupt中断线程-----抛出InterruptedException异常,中断状态:false
interrupt中断线程---
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ms.studyjava.threads.demo1.ThreadStopMethods.run(NewThread.java:74)
interrupt中断线程---
interrupt中断线程---
interrupt中断线程---
interrupt中断线程---
......无限循环.......
出现这种情况就需要我们在线程里面再次手动的中断线程。避免线程一直在执行
class ThreadStopMethods extends Thread {
@Override
public void run() {
//判断当前线程是否被中断,没有中断就继续执行业务。返回true表示已中断
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"--抛出InterruptedException异常,中断状态:"+Thread.currentThread().isInterrupted());
//再次手动中断线程
Thread.currentThread().interrupt();
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
System.out.println(Thread.currentThread().getName() + "已被中断,中断状态:" + Thread.currentThread().isInterrupted());
}
}
interrupt中断线程---
interrupt中断线程---
interrupt中断线程---
interrupt中断线程---
interrupt中断线程---
interrupt中断线程-----抛出InterruptedException异常,中断状态:false
interrupt中断线程---
interrupt中断线程---已被中断,中断状态:true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ms.studyjava.threads.demo1.ThreadStopMethods.run(NewThread.java:74)
线程状态
Sleep方法
将线程从运行状态变成阻塞状态。举个例子:比如你在公司用微波炉热饭,热到一半发现自己有急事要出去一趟,这时候你把饭拿走,等事情处理完后在进行热饭,在你走的这段时间微波炉可能已经被他人使用,你再次回来就需要排队使用了。
yield方法(用的较少)
将线程从运行状态变成可运行状态,举个例子:你在公司正在用微波炉热饭,这时候看到你好朋友都一起来了,于是你把饭拿出来,说大家一起抢下,谁速度快就就热饭,这个时候你可能还可以继续热饭。也就是说,yield的线程,可能再次继续被执行。
run和statr方法理解
run是启动一个线程。start是将创建的线程放入就绪装备等待run方法执行
/**
* run和start
* **/
class RunStatrMethods extends Thread{
@Override
public void run() {
System.out.println("线程名称:"+Thread.currentThread().getName());
}
}
public void runStatr(){
RunStatrMethods thread = new RunStatrMethods();
thread.setName("RunStatrMethods线程");
//直接调用run方法
thread.run();
//调用start
//thread.start();
}
线程名称:main
发现直接调用run方法,打印的线程名称居然是main,这是为什么呢?再看下调用start结果
线程名称:main
线程名称:RunStatrMethods线程
很惊讶的方法run和statr都执行RunStatrMethods 里面的run方法了。但是结果却不一样。
解释:Main方法的是一个单独的线程,在调用run方法之前,这里面没有其他线程调用start进行启动。所以RunStatrMethods .run()实际上是main函数的线程去调用了Thread里面的run方法,当start启动了RunStatrMethods 线程时候,这时候才有RunStatrMethods 线程自己去调用Thread里面的run方法,