线程的创建
1.创建一个类继承Thread类并重写run方法
class MyTheard extends Thread{
@Override
public void run() {
while(true) {
System.out.println("hello thread!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
MyTheard myTheard=new MyTheard();
myTheard.start();
while(true){
System.out.println("hello main!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.创建一个类实现Runnable接口,并重写run方法
class MyRunnable implements Runnable{
@Override
public void run() {
while(true){
System.out.println("hello thread!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
MyRunnable myRunnable=new MyRunnable();
Thread thread=new Thread(myRunnable);
thread.start();
while(true){
System.out.println("hello main!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.使用匿名内部类,创建Thread子类,重写run方法
public class Demo3 {
public static void main(String[] args) {
Thread thread=new Thread(){
@Override
public void run() {
while(true){
System.out.println("hello thread!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
while(true){
System.out.println("hello main!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.new一个Runnable实例传给Thread构造方法,并重写run方法
public class Demo4 {
public static void main(String[] args) {
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("hello thread!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
while(true){
System.out.println("hello main!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
5.使用lambda表达式创建线程
public class Demo5 {
public static void main(String[] args) {
Thread thread=new Thread(()->{
while(true){
System.out.println("hello thead!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
while(true){
System.out.println("hello main!");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程的中断
1.手动设计标记位
我们想要中断一个线程,如果那个线程一直在执行,我们可以在run方法中,手动设定一个标记位,假设默认情况为false,然后线程在执行前任务前都要判断标记位,当我们在主线程中更改标记位为true,此时执行的线程被中断,否则继续执行。
public class Demo {
public static boolean flag=false;//设定标记
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while (!flag){
System.out.println("执行线程任务!");
try {
Thread.sleep(1000);//线程每休眠1s就执行一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();//启动线程
Thread.sleep(4000);//主线程休眠4s后执行
flag=true;//更改标记
}
}
执行结果:
2.使用Thread对象中得标记位
先调用的是currentThread()方法获取当前线程对象,然后调用该线程对象中的isInterrupted()方法获取标记位,类似我们之前手动设置的flag标记位。线程每次执行任务前都要判断标记位,而我们只需要在main线程中修改标记位就能中断线程的执行。中断线程调用的是interrupted()方法。
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
System.out.println("线程执行任务!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
Thread.sleep(4000);//主线程休眠
t1.interrupt();//中断t1线程
}
}
运行结果:
和我们预期似乎有差别,线程在执行到了一定时间后,抛出异常后继续执行,并未中断,原因是 因为使用interrupt方法触发中断机制时,如果该线程是Runnable状态则设定标志位,如果该线程是阻塞状态(sleep等),会抛出异常,虽然此时interrupt仍然会设定标志位,但是sleep、wait等方法会清除这个标记位。所以也就是为什么线程会继续执行。此时如果我们还是非要中断该线程,就得在抛出异常时,在catch代码块内,不仅要抛异常,还需要跳出循环执行的线程任务(break即可)。
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
System.out.println("线程执行任务!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("线程任务结束!");
break;
}
}
});
t1.start();
Thread.sleep(4000);//主线程休眠
t1.interrupt();//中断t1线程
}
}
执行结果:
3.使用Thread类中的标记位
这是使用Thread类中的静态方法interrupted()也能够访问类中的标记位,而且一般一个程序中只有一个,我们可以用它来作为线程中断的标记位。而修改标记位还是使用interrupt方法来中断线程执行。
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while (!Thread.interrupted()){
System.out.println("线程执行任务!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("线程任务结束!");
break;
}
}
});
t1.start();
Thread.sleep(4000);
t1.interrupt();//中断t1线程
}
}
执行结果:
线程等待
使用join()方法,注意join方法的使用,例如有两个线程,一个线程A,一个线程B,在A中使用B.join(),意思是A线程要等待B线程执行结束后才能执行(A线程阻塞)。同理在B中使用A.join(),意思是B线程要等待A线程执行结束后才能执行(B线程阻塞)。
public class Demo {
public static final long COUNT=10_000_000_000L;
public static void main(String[] args) {
long beg=System.currentTimeMillis();
Thread thread1=new Thread(()->{
long a=0;
for (long i = 0; i < COUNT; i++) {
a++;
}
},"这里可以放线程的名字");
Thread thread2=new Thread(()->{
long a=0;
for (long i = 0; i <COUNT ; i++) {
a++;
}
});
thread1.start();
thread2.start();
try {
//main线程阻塞,等线程1和线程2执行结束后,main线程才能继续执行
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long end=System.currentTimeMillis();
System.out.println("并发执行时间:"+(end-beg)+"ms");
}
}
线程休眠
使用sleep(long)方法,会使当前调用的该方法的线程休眠一段时间,这段时间内线程处于阻塞等待状态,该时间是自己设定,等一段时间过后,该线程就会继续执行。
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while (true){
System.out.println("线程执行任务!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
获取线程实例
获取当前线程引用使用 Thread.currentThread()方法,在哪个线程内调用,就是获取哪个线程的引用。之前我们用这个对象引用获取isInterrupted()方法判断当前线程是否是处于中断状态。