一、创建线程
继承Thread类,重写run方法
// 继承Thread类创建线程public class Thread01 {public static void main(String[] args) {// 创建Cat对象当作线程使用Cat cat = new Cat();// public synchronized void start() {// start0();// }// private native void start0(); 本地方法,jvm调用。cat.start();// 启动线程 -> 会执行Cat的run方法// 不能是cat.run(); run方法是一个普通的方法,没有启动线程,会把run方法执行完再继续// main线程启动了一个子线程Thread-0,主线程不会阻塞,会继续执行// 主线程和子线程交替执行for(int i = 0;i<10;i++){System.out.println("主线程执行"+ Thread.currentThread().getName());}}}// 类继承了Thread类,该类就可以当作线程使用// run Thread类 实现了Runnable接口的run方法class Cat extends Thread{int times = 0;@Overridepublic void run() {while (true){System.out.println("输出" + (++times) + "线程名=" +Thread.currentThread().getName());try {Thread.sleep(1000); // 每隔1秒} catch (InterruptedException e) {e.printStackTrace();}if(times == 80) {break; // 当times到80 退出循环,线程退出}}}}
start()方法调用start0()方法后,该线程并不一定会立马执行,只是将线程变成可运行状态,什么时候执行取决于CPU
实现Runnable接口,重写run方法
java单继承,如果一个类已经继承了某个父类,这时不能再继承Thread类
实现Runnable接口方式更适合多个线程共享一个资源的情况,且避免了单继承的限制
// 实现接口Runnablepublic class Thread02 {public static void main(String[] args) {Dog dog = new Dog(); // 不能调用start// 创建Thread对象,把dog对象放入ThreadThread thread = new Thread(dog);thread.start();}}class Dog implements Runnable{int count = 0;@Overridepublic void run() {while (true) {System.out.println(++count + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}
多线程
// 多线程 两个子线程public class Thread03 {public static void main(String[] args) {T1 t1 = new T1();T2 t2 = new T2();Thread thread1 = new Thread(t1);Thread thread2 = new Thread(t2);thread1.start();thread2.start();}}class T1 implements Runnable {private int count = 0;@Overridepublic void run() {while (true){System.out.println("hello" + (++count));try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}class T2 implements Runnable {private int count = 0;@Overridepublic void run() {while (true) {System.out.println("hi" + (++count));try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}
二、线程终止
- 线程完成后,会自动退出
变量控制run方法退出的方式停止线程,即通知方式
public class ThreadExit {public static void main(String[] args) throws InterruptedException {T t = new T();t.start();// 希望主线程控制t,终止,控制loop变量 -> 通知方式// 主线程休眠10秒(此时子线程还在运行),再通知t退出Thread.sleep(10000);t.setLoop(false);}}class T extends Thread {private boolean loop = true; // 控制变量private int count;@Overridepublic void run() {while (loop) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("T 运行中" + (++count));}}public void setLoop(boolean loop) {this.loop = loop;}}
三、线程常用方法
setName 设置线程名称,使之与参数name相同
- getName 返回该线程的名称
- start 使该线程开始执行
- run 调用线程对象run方法
- setPriority 更改线程的优先级
- getPriority 获取线程的优先级
- sleep 在指定的毫秒数内让当前正在执行的线程休眠
interrupt 中断线程,一般用于中断正在休眠的线程
public class ThreadMethod01 {public static void main(String[] args) throws InterruptedException {Td t = new Td();t.setName("测试");t.setPriority(Thread.MIN_PRIORITY);t.start(); // 启动子线程// 主线程打印5个hi,就中断子线程休眠for (int i = 0; i < 5; i++) {Thread.sleep(1000);System.out.println("hi" + i);}System.out.println(t.getName()+ " 线程的优先级 = " + t.getPriority());t.interrupt(); // 中断t线程的休眠}}class Td extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + " 输出");try {System.out.println(Thread.currentThread().getName() + " 休眠");Thread.sleep(200);} catch (InterruptedException e) {// 线程执行到一个interrupt方法时,会catch一个异常System.out.println(Thread.currentThread().getName() + " 被中断了");}}}}
yield 礼让 不一定成功,礼让的时间不确定
join 插队,一定成功,执行完插入的线程 ```java public class ThreadMethod02 { public static void main(String[] args) throws InterruptedException {
T5 t5 = new T5();t5.start();for (int i = 1;i<=20;i++){Thread.sleep(1000);System.out.println("主线程"+i);if(i == 5) {System.out.println("让子线程先做");t5.join(); // 相当于让t5先执行 join 一定会成功// Thread.yield(); 礼让 不一定成功System.out.println("主线程继续");}}
} }
class T5 extends Thread { @Override public void run() { for (int i = 1; i <= 20; i++) {
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程" + i);}}
}
<a name="gigxV"></a>## 四、用户线程和守护线程1. 用户线程(工作线程),当线程的任务执行完或通知方式结束1. 守护线程,一般是为工作线程服务,当所有的用户线程结束,守护线程自动结束 如 垃圾回收```javapublic class ThreadMethod03 {public static void main(String[] args) throws InterruptedException {MyDaemonThread myDaemonThread = new MyDaemonThread();// 当main线程结束后,子线程自动结束 将子线程设为守护线程myDaemonThread.setDaemon(true);myDaemonThread.start();for (int i = 1; i<=10;i++){System.out.println("main 工作");Thread.sleep(1000);}}}class MyDaemonThread extends Thread {public void run(){for (;;) { // 无限循环try {Thread.sleep(1000);} catch (InterruptedException e){e.printStackTrace();}System.out.println("hhh");}}}
五、线程的生命周期
状态:
- NEW 尚未启动的线程状态
- RUNNABLE Java虚拟机中执行的线程状态 可以分为Ready和Running两个
- BLOCKED 阻塞
- WAITING 等待另一个线程执行特定动作的线程状态
- TIMEED_WAITING 等待另一个线程执行动作达到指定等待时间的线程状态
TERMINATED 已退出
public class ThreadState_ {public static void main(String[] args) throws InterruptedException {T6 t6 = new T6();System.out.println(t6.getName()+"状态" + t6.getState());t6.start();while (Thread.State.TERMINATED != t6.getState()){System.out.println(t6.getName() + " 状态" + t6.getState());Thread.sleep(500);}System.out.println(t6.getName()+ " 状态" + t6.getState() );}}class T6 extends Thread {@Overridepublic void run() {while (true){for (int i = 0; i < 10; i++) {System.out.println("hi"+i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}
六、线程的同步 Synchronized
同步代码块
synchronized (对象) {<br />}
同步方法
public synchronized void m(String name){
}
七、互斥锁
每个对象都对应于一个可称为互斥锁的标记,保证在任一时刻,只能有一个线程访问该对象
非静态的同步方法的锁可以是this,也可以是其他对象
静态的同步方法的锁为当前类本身
public class SellTicket {public static void main(String[] args) {SellTicket03 sellTicket03 = new SellTicket03();new Thread(sellTicket03).start();new Thread(sellTicket03).start();new Thread(sellTicket03).start();}}//实现接口方式, 使用synchronized实现线程同步class SellTicket03 implements Runnable {private int ticketNum = 100;//让多个线程共享 ticketNumprivate boolean loop = true;//控制run方法变量Object object = new Object();//同步方法(静态的)的锁为当前类本身//1. public synchronized static void m1() {} 锁是加在 SellTicket03.class//2. 如果在静态方法中,实现一个同步代码块./*synchronized (SellTicket03.class) {System.out.println("m2");}*/public synchronized static void m1() {}public static void m2() {synchronized (SellTicket03.class) {System.out.println("m2");}}//1. public synchronized void sell() {} 就是一个同步方法//2. 这时锁在 this对象//3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在this对象public /*synchronized*/ void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法synchronized (/*this*/ object) {if (ticketNum <= 0) {System.out.println("售票结束...");loop = false;return;}//休眠50毫秒, 模拟try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"+ " 剩余票数=" + (--ticketNum));}}@Overridepublic void run() {while (loop) {sell();//sell方法是一共同步方法}}}
八、死锁
多个线程占用了对方的资源,但不相让
public class DeadLock_ {public static void main(String[] args) {DeadLockDemo A = new DeadLockDemo(true);A.setName("A线程");DeadLockDemo B = new DeadLockDemo(false);B.setName("B线程");A.start();B.start();}}//线程class DeadLockDemo extends Thread {static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用staticstatic Object o2 = new Object();boolean flag;public DeadLockDemo(boolean flag) {this.flag = flag;}@Overridepublic void run() {//1. 如果flag 为 T, 线程A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁//2. 如果线程A 得不到 o2 对象锁,就会Blocked//3. 如果flag 为 F, 线程B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁//4. 如果线程B 得不到 o1 对象锁,就会Blockedif (flag) {synchronized (o1) {//对象互斥锁System.out.println(Thread.currentThread().getName() + " 进入1");synchronized (o2) {System.out.println(Thread.currentThread().getName() + " 进入2");}}} else {synchronized (o2) {System.out.println(Thread.currentThread().getName() + " 进入3");synchronized (o1) {System.out.println(Thread.currentThread().getName() + " 进入4");}}}}}
![U)7UUVCV}F]]FZ3QC@DI0BB.png](/uploads/projects/quantianbuhuoyue@abmz1b/5e74ebd4ea141d6915ba34ce1325121d.png)
