多线程意义 在同一时间需要完成多项任务时需要多线程。
参考视频:看动画,学Java多线程教程
创建线程三种方式 继承Thread类 1 2 3 4 5 6 7 8 package main;public class MyThread extends Thread { @Override public void run () { System.out.println("将执行任务写到run方法里" ); } }
1 2 3 4 5 6 7 package main;public class Main { MyThread mythread = new MyThread (); myThread.start(); }
实现Runnable接口 Runnable没有启动线程的能力,需要搭配thread来用。
1 2 3 4 5 6 7 8 package main;public class Task implements Runnable { @Override public void run () { System.out.println("将执行任务写到run方法里" ); } }
1 2 3 4 5 6 7 8 9 10 11 package main;public class Main { public static void main (String[] args) { Task task = new Task (); Thread thread = new Thread (task); thread.start(); } }
实现Callable接口 Callable没有启动线程的能力,需要搭配thread来用。同时,Callable需要返回泛型。
1 2 3 4 5 6 7 8 9 package main;import java.util.concurrent.Callable;public class Result implements Callable <String> { @Override public String call () throws Exception { return "将要执行的任务写在call方法里面并返回执行的结果" ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package main;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class Main { public static void main (String[] args) throws InterruptedException{ Result result = new Result (); FutureTask<String> futureTask = new FutureTask <>(result); Thread thread = new Thread (futureTask); thread.start(); try { String str = futureTask.get(); System.out.println(str); }catch (InterruptedException e){ e.printStackTrace(); }catch (ExecutionException e){ e.printStackTrace(); } } }
总结
创建方式
使用场景
Thread
单继承(不建议在开发用)
Runnable
无返回任务
Callable
有返回任务
获取当前执行任务的线程 currentThread() 1 2 3 4 5 6 7 8 9 package main;public class Main { public static void main (String[] args) { Thread thread = Thread.currentThread(); System.out.println(thread); } }
输出结果:
main:线程的名称
5:线程的优先级
main:线程所属的线程组名称
获取和设置线程的名称、优先级 获取线程名称 getName() 1 String str = thread.getName();
设置线程名称 setName(String name) 1 thread.setName("在这里设置名称" );
获取线程优先级 getPriority() 1 int priority = thread.getPriority();
设置线程优先级 setPriority()
常用优先级常量 1 2 3 4 5 6 public final static int MIN_PRIORITY = 1 ;public final static int MAX_PRIORITY = 10 ;public final static int NORM_PRIORITY = 5 ;
1 2 //调用优先级常量(最大) thread.setPriority(Thread.MAX_PRIORITY);
run()与start()区别 位置 虽然都在Thread,但是run方法重写自Runnable接口。
类型 run是非同步方法,start是同步方法。
作用 run存放执行代码,start启动线程,启动后执行run方法。
是否产生线程 run不产生线程,start只产生一个线程。
1 2 3 4 5 6 7 8 9 10 11 12 package main;public class Task implements Runnable { @Override public void run () { Thread thread = Thread.currentThread(); String threadName = thread.getName(); System.out.println(threadName); } }
1 2 3 4 5 6 7 8 9 10 package main;public class Main { public static void main (String[] args) { Task task = new Task (); Thread thread = new Thread (task); thread.run(); } }
输出结果:
调用次数 run可调用无限次,start只能调用一次。
进入休眠 sleep() 1 2 3 4 5 public static native void sleep (long millis) throws InterruptedException
1 2 3 4 5 6 public static void sleep (long millis, int nanos) throw InterruptedException
中断线程 停止正在运行的线程 中断标记 interrupt() 1 2 3 4 5 6 7 8 9 10 package main;public class Task implements Runnable { @Override public void run () { while (true ){ System.out.println("正在运行" ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 package main;public class Main { public static void main (String[] args) throws InterruptedException{ Task task = new Task (); Thread thread = new Thread (task); thread.start(); Thread.sleep(1000 ); thread.interrupt(); } }
输出结果:
1 2 3 4 正在运行 正在运行 正在运行 ...(不会停止)
原因:interrupt只是标记,中断操作要在run()方法里面操作。
中断操作 isInterrupt()和interrupted()
方法名称
类型
作用
isInterrupted
非静态方法
判断线程是否被中断
interrupted
静态方法(可通过类直接调用)
判断线程是否被中断,并清除中断标记
isInterrupted():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main;public class Task implements Runnable { @Override public void run () { while (true ){ Thread thread = Thread.currentThread(); if (thread.isInterrupted()){ break ; } System.out.println("正在运行" ); } } }
interrupted():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main;public class Task implements Runnable { @Override public void run () { while (true ){ if (Thread.interrupted()){ break ; } System.out.println("正在运行" ); } } }
一样效果,可结束线程
isInterrupted():
1 2 3 4 5 6 7 8 9 ... @Override public void run () { while (true ){ Thread thread = Thread.currentThread(); System.out.println(thread.isInterrupted()); } }
输出结果:
1 2 3 4 5 6 7 false false ... false true true ...
interrupted():
1 2 3 4 5 6 7 8 ... @Override public void run () { while (true ){ System.out.println(Thread.interrupted()); } }
输出结果:
1 2 3 4 5 6 7 8 false false ... false true false false ...
停止休眠中的线程 1 2 3 4 5 6 7 8 9 10 ... @Override public void run () { try { Thread.sleep(10000 ); }catch (InterruptedException e){ e.printStackTrace(); } }
输出结果:
1 2 3 4 java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at com.example.demo.Task.run(Task.java:8 ) at java.base/java.lang.Thread.run(Thread.java:833 )
让别的线程得到更多执行权 yield() 在run()方法中使用Thread.yield()方法可以让别的线程得到更多执行权,但不是放弃执行权。
1 2 3 4 5 6 7 8 9 public class PrintTask implements Runnable { @Override public void run () { while (ValueTask.value==0 ){ Thread.yield (); } System.out.println(ValueTask.value); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class ValueTask implements Runnable { public static int value = 0 ; @Override public void run () { System.out.println(6 ); try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } value = 100 ; } }
等待线程死亡 join() 在一个线程中的run()方法中调用另一个线程的join()方法时,调用线程将被阻塞,直到另一个线程执行完为止(一定要在join()之前先start(),不然直接join直接结束)
1 2 3 public final void join () throws InterruptedException { join(0 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Task implements Runnable { @Override public void run () { JoinTask joinTask = new JoinTask (); Thread joinThread = new Thread (joinTask); System.out.println(JoinTask.value); try { joinThread.start(); joinThread.join(); System.out.println(JoinTask.value); }catch (InterruptedException e){ e.printStackTrace(); } } }
1 2 3 4 5 6 7 public class JoinTask implements Runnable { public static int value = 0 ; @Override public void run () { value = 100 ; } }
守护线程(后台线程) daemon() 设置守护线程 setDaemon() 1 public final void setDaemon (boolean on)
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Main { public static void main (String[] args) { PrintTask printTask = new PrintTask (); Thread printThread = new Thread (printTask); printThread.setDaemon(true ); printThread.start(); try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 public class PrintTask implements Runnable { @Override public void run () { while (true ){ System.out.println("线程运行中" ); } } }
线程在主线程结束时结束。
判断线程是否为后台线程 isDaemon() 1 public final boolean isDaemon ()
线程是否死亡 isAlive() 1 public final native boolean isAlive () ;
*同步锁 synchronized 线程获得同步锁对象后,只能该线程占用这个对象,其他线程必须等待该线程释放了该对象才能占用这个对象。解决线程安全问题。
1 2 3 synchronized(object){} 访问修饰符 synchronized 返回值类型 方法名(参数类型 参数名称){} 访问修饰符 static synchronized 返回值类型 方法名(参数类型 参数名称){}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Main { public static void main (String[] args) { TicketingTask ticketingTask = new TicketingTask (); Thread ticketingThread1 = new Thread (ticketingTask); Thread ticketingThread2 = new Thread (ticketingTask); Thread ticketingThread3 = new Thread (ticketingTask); ticketingThread1.setName("1号" ); ticketingThread2.setName("2号" ); ticketingThread3.setName("3号" ); ticketingThread1.start(); ticketingThread2.start(); ticketingThread3.start(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TicketingTask implements Runnable { private int ticket = 10 ; @Override public void run () { while (ticket>0 ){ synchronized (this ){ if (ticket>0 ){ System.out.println(ticket+"号票卖出,窗口为" +Thread.currentThread().getName()); ticket--; } } } } }
可同步的内容 同步代码块
同步方法 1 2 public synchronized void show (String name) {}
同步类 1 synchronized (类名.class){}
死锁 死锁指2个或2个以上的线程争夺彼此的锁,造成阻塞,程序永远处于阻塞状态。
死锁产生的条件 两个或两个以上的线程
两个或两个以上的锁
两个或两个以上的线程持有不同锁
持有不同锁的线程争夺对方的锁
示例 1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { LockA lockA = new LockA (); LockB lockB = new LockB (); lockA.start(); lockB.start(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class LockA extends Thread { @Override public void run () { printA(); } public static synchronized void printA () { try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("A" ); LockB.printB(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class LockB extends Thread { @Override public void run () { printB(); } public static synchronized void printB () { try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("B" ); LockA.printA(); } }
等待唤醒机制 wait(), notify() wait() 1 2 3 4 5 6 public final void wait () throws InterruptedException
notify() 1 2 3 4 5 public final native void notify ()
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class LockA extends Thread { @Override public void run () { printA(); } public static synchronized void printA () { try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("A" ); synchronized (LockB.class){ LockB.class.notify(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class LockB extends Thread { @Override public void run () { printB(); } public static synchronized void printB () { try { Thread.sleep(1000 ); }catch (InterruptedException e){ e.printStackTrace(); } try { LockB.class.wait(); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("B" ); } }
唤醒所有线程 notifyAll() ,使用方法和notify类似 wait()和sleep()区别
sleep()
wait()
位置
Thread类
Object类
是否需要当前线程拥有锁?
不需要
需要
是否支撑手动唤醒?
不支持
notify()、notifyAll()
是否支持自动唤醒?
sleep(long millis)
wait(long timeout)
是否支持中断?
interrupt
interrupt
是否释放锁?
否
是
线程状态
TIMED_WAITING
WAITING、TIMED_WAITING