线程的操作
1.启动一个线程
覆写run方法创建一个线程对象,对象被创建出来并不意味着线程就开始运行了
run()方法相当于提供给线程要做的事情的清单。
线程对象可以认为是让线程准备好,调用过来。
这时候调用start()方法,就可以使线程执行起来了。
中断一个线程
线程一旦进入到工作状态,就会按照run()方法中的程序去执行,不完成不会结束。
但是有时候要增加一些机制,让正在运行的线程停止下来。
让线程停止的方式:
1.通过共享的标记来进行沟通
2.通过interrupt()(打断)方法来通知
//停止线程的方式
public class ThreadDemo {
private static class MyRunnable implements Runnable{
//volatile修饰变量,不允许线程内部缓存和重排序,也就是直接修改内存
//定义线程初始为不主动放弃状态
public volatile boolean isQuit=false;
@Override
public void run() {
while(!isQuit){
System.out.println(Thread.currentThread().getName()+":我正在运行");
try {
//定义每1秒休眠一次
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":停下来了");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target=new MyRunnable();
//创建线程对象并且命名为小代
Thread thread=new Thread(target,"小代");
System.out.println(Thread.currentThread().getName()+":让小代这个线程开始运行");
thread.start();
//定义每10秒休眠一次
Thread.sleep(10*1000);
System.out.println(Thread.currentThread().getName()+":让小代这个线程停止运行");
//让线程初始状态变为不运行,就不执行run()方法了。
target.isQuit=true;
}
}
/*
执行结果:
main:让小代这个线程开始运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
小代:我正在运行
main:让小代这个线程停止运行
小代:停下来了
*/
volatile修饰变量,不允许线程内部缓存和重排序,也就是直接修改内存
/停止线程的方式
//调用interrupt()方法来通知
public class ThreadDemo2 {
private static class MyRunnable implements Runnable{
@Override
public void run() {
while(!Thread.interrupted()){
System.out.println(Thread.currentThread().getName()+":别管我,我正在干活");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+":有情况,现在停止线程");
break;
}
}
System.out.println(Thread.currentThread().getName()+":停下来了");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target=new MyRunnable();
Thread thread=new Thread(target,"小代");
System.out.println(Thread.currentThread().getName()+":让小代开始工作");
thread.start();
Thread.sleep(10*1000);
System.out.println(Thread.currentThread().getName()+":让小代停下来");
thread.interrupt();
}
}
/*
执行结果:
main:让小代开始工作
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
小代:别管我,我正在干活
main:让小代停下来
java.lang.InterruptedException: sleep interrupted
小代:有情况,现在停止线程
at java.lang.Thread.sleep(Native Method)
小代:停下来了
at 多线程复习2.ThreadDemo2$MyRunnable.run(ThreadDemo2.java:13)
at java.lang.Thread.run(Thread.java:748)
*/
通过Thread对象调用Interrupt方法通知该线程停止运行
thread收到通知的方法有两种:
1.如果线程调用了 wait/join/sleep 等 方法而阻塞挂起,则以interruptedException异常的形式通知,清除中断标志。
2.否则只是内部的一个中断标志被设置thread可以通过
1、Thread.interrupted判断当前线程的中断标志被设置,清除中断标志。
2、Thread.currentThread().isInterrupted()判断指定线程的中断标志被设置,不清除中断标志。
使用interrupt通知,线程会收到的更及时,即时在sleep状态也能马上收到。
如果线程调用了sleep、wait、join等方法,主线程通过interrput的方法通知该线程,以interruptedException异常形式通知,并且会清除中断标志。
如果线程没有调用上面的方法,那么就只是内部的一个中断标志被设置。
1、thread如果通过Thread.interrupted判断当前线程的中断标志,判断完成之后中断标志就会被清除。
2、thread如果通过Thread.currentThread.interruoted判断当前线程的中断标志,只是判断一下,并不会清除。
/线程sleep,通过异常收到了中断的情况
public class ThreadDemo3 {
private static class MyRunnable implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("通过异常收到了中断情况");
}
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
public static void main(String[] args) {
MyRunnable target =new MyRunnable();
Thread thread=new Thread(target,"小代");
thread.start();
thread.interrupt();
}
}
/*
执行结果:
false
false
false
false
false
false
false
false
false
false
public class ThreadDemo4 {
private static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.interrupted());
}
}
}
public static void main(String[] args) {
MyRunnable target=new MyRunnable();
Thread thread=new Thread(target,"小代");
thread.start();
thread.interrupt();
}
}
/*
执行结果:
true 一开始是true,,后边的标志位都被清除了,所以是false
false
false
false
false
false
false
false
false
false
*/
public class ThreadDemo5 {
private static class MyRunnbale implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread .currentThread().isInterrupted());
}
}
}
public static void main(String[] args) {
MyRunnbale target=new MyRunnbale();
Thread thread=new Thread(target,"小代");
thread.start();
thread.interrupt();
}
}
/*
执行结果:
true 全部是true,因为标志位没有被清除
true
true
true
true
true
true
true
true
true
*/
调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。
isInterrupted() 判定当前线程是否处于中断状态。
static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。
方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()。
等待一个线程join()
有的情况下,我们需要等待一个线程执行完成之后,才能进行下一步的工作。这个时候我们需要一个方法明确等待线程的结束。
/join,等待一个线程结束来执行下一个线程
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Runnable target=()->{
for (int i = 0; i <10; i++) {
System.out.println(Thread.currentThread().getName()+":我还在工作!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":我结束了!");
};
Thread thread1=new Thread(target,"小代");
Thread thread2=new Thread(target,"小赵");
System.out.println("让小代先开始工作");
thread1.start();
thread1.join();
System.out.println("小代工作结束了,让小赵开始工作");
thread2.start();
thread2.join();
System.out.println("小赵工作结束了");
}
}
/*
执行结果:
让小代先开始工作
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我还在工作!
小代:我结束了!
小代工作结束了,让小赵开始工作
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我还在工作!
小赵:我结束了!
小赵工作结束了
获取当前线程的引用
public static Thread currentThread();
返回当前线程对象的引用。
public class Threaddemo{
public static void main(String [] args){
Thread thread=new Thread.currentThread();
System.out.println(thread.getName());
}
}
休眠当前线程
由于线程的调度是不可控制的,所以这个方法只能保证休眠时间是大于等于休眠时间的设定值。
public class main2 {
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(3*1000);
System.out.println(System.currentTimeMillis());
}
}
/*
执行结果:
1578991732704
1578991735704
*/
线程的状态
//获取线程的所有状态
public class ThreadState {
public static void main(String[] args) {
for(Thread.State state:Thread.State.values()){
System.out.println(state);
}
}
}
/*
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
*/
线程的状态及状态转移的意义
当线程准备好去运行,等待服务,就进入到Runnable状态,这个状态包含正在执行的线程,也包含可被执行的线程,也就是正在排队的线程,是否开始执行,要看服务器的调度。
当线程等待其他外部事件的时候,会进入到BLOCK、WATING 、TIMED_WAITING状态
只要线程不是NEW状态和TREMINATED状态,那么线程都是活着的线程。也就是该线程调用isAlive()方法为true
观察线程的状态和转移
关注NEW、RUNNABLE、TERMINATED状态转换
public class ThreadStateTransfer {
public static void main(String[] args) {
Thread t=new Thread(()->{
for (int i = 0; i <1000_0000 ; i++) {
}
},"小代");
System.out.println(t.getName()+":"+t.getState());
t.start();
while(t.isAlive()){
System.out.println(t.getName()+":"+t.getState());
}
System.out.println(t.getName()+":"+t.getState());
}
}
关注 WAITING BLOCKED TIMED_WAITING状态的转换
public class ThreadStateTransfer2 {
public static void main(String[] args) throws InterruptedException {
Object object=new Object();
Thread t=new Thread(()->{
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 1000_0000; i++) {
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println(t.getState());
t.start();
System.out.println(t.getState());
Thread.sleep(10);
synchronized (object){
for (int i = 0; i <10; i++) {
System.out.println(t.getState());
}
object.notify();
}
while (t.isAlive()){
System.out.println(t.getState());
}
}
}
yield()方法
yield()只是让出CPU,并不会改变自己的状态,就是从正在运行的状态变成待运行的状态。
//yield()让出CPU
public class ThreadStateTransfer3 {
public static void main(String[] args) {
Thread thread1=new Thread(()->{
while(true){
System.out.println(Thread.currentThread().getName()+":我正在工作");
//Thread.yield();
}
},"小代");
Thread thread2=new Thread(()->{
while(true){
System.out.println(Thread.currentThread().getName()+":我正在工作");
}
},"小赵");
thread1.start();
thread2.start();
}
}
//打印出来小赵的工作多于小代的工作。