单线程:同时允许执行一个线程
多线程:同一个时刻,可以执行多个线程
并发:同一个时刻,多个任务交替执行,造成"貌似同时"的错觉,简单的说,单核CPU实现的多任务就是并发
并行:同一个时刻,多个任务同时执行。多核CPU可以同时执行
在Java中线程来使用有两种方法
基础Thread类,重写run方法
实现Runnable接口,重写run方法

package com.hspedu.threaduse;/** * @author DL5O * @version 1.0 * 通过继承Thread 类创建线程 */public class Thread01 { public static void main(String[] args) throws InterruptedException { //创建Cat对象,可以当做线程使用 Cat cat = new Cat(); //启动线程,调用start的时候还调用run方法 cat.start();//最终执行 -> cat的run方法 //cat.run(); //如果这样写,run方法就是一个普通的方法, // 是由主线程调用了,并没有真正的开线程, // 会阻塞在这里,执行完毕后才会继续执行下面的代码 //说明:当main线程启动一个子线程thread-0,主线程不会阻塞, // 即不会等待cat.start执行完毕后再往下执行 //主线程中如果后面还有代码的话,还会继续执行 //这时我们的主线程和主线程 是交替执行的 System.out.println("继续执行~~,"+Thread.currentThread().getName()); for (int i = 0; i < 60; i++) { System.out.println("主线程 i=" + i); //休眠1秒 Thread. sleep(1000); } }}//1.当一个类继承了Thread 类,该类就可以当做一个线程使用//2.我们会重写run方法,写上自己的业务逻辑//3.run方法在Thread也是实现了Runnable 接口的run方法class Cat extends Thread { int times = 0; @Override public void run() {//重写run方法,写上自己的业务逻辑 while (true) { //每隔一秒钟,输出"喵喵,我是小猫咪" System.out.println("喵喵,我是小猫咪" + (++times) + ",线程名称=" + Thread.currentThread().getName()); //让线程休眠1秒钟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (times == 80) { break;//当times 等于80就退出这个while循环,这时线程就退出了 } } }}car.start() 方法时会开启一个新的线程,这个线程是mian线程的子线程car.start()是非阻塞的,即不会等到这个方法执行完后才继续往下执行car.start()线程开启后,会去调用run方法!!执行过程
(1)public synchronized void start() { start0();}(2)//start0() 是本地方法,是JVM调用,底层是c/c++实现的//真正实现多线程的是start0(),而不是run方法 private native void start0();实现runnable接口
说明:
Runnalb接口来创建线程
package com.hspedu.threaduse;/** * @author DL5O * @version 1.0 * 通过实现接口Runnable 来开发线程 */public class Thread02 { public static void main(String[] args){ Dog dog = new Dog(); //dog.start(); 这里不能调用start //创建了Thread对象,把 dog对象,实现了Runnable,放入thread Thread thread = new Thread(dog); thread.start(); /*Tiger tiger = new Tiger();//实现了runnable接口 ThreadProxy threadProxy = new ThreadProxy(tiger); threadProxy.start(); System.out.println("哈哈哈哈");*/ System.out.println("哈哈哈"); }}class Animal{}class Tiger extends Animal implements Runnable{ @Override public void run() { System.out.println("老虎嗷嗷叫..."); }}//模拟了最简的Thread类class ThreadProxy implements Runnable{//可以当做ThreadProxy ,线程代理 private Runnable target = null;//属性,类型是Runnable @Override public void run() { if(target != null){ target.run();//进行动态绑定 运行类型是tiger,即实现了Runnable的类 } } public ThreadProxy(Runnable target) { this.target = target; } public void start(){ start0();//这个方法是真正实现多线程的方法 } private void start0() { run(); }}class Dog implements Runnable{ int count = 0; @Override public void run() {//普通方法,并没有启动线程 while(true){ System.out.println("小狗汪汪叫..hi" + (++count) + Thread.currentThread().getName()); //休眠一秒 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(count == 10){ break; } } }}
package com.hspedu.threaduse;/** * @author DL5O * @version 1.0 * main 线程启动两个子线程 */public class Thread03 { public static void main(String[] args) { T1 t1 = new T1(); T2 t2 = new T2(); Thread thread1 = new Thread(t1);//创建t1线程,用于输出hello,world Thread thread2 = new Thread(t2);//创建t2线程,用于输出hi thread1.start(); thread2.start(); }}class T1 implements Runnable { int count = 0; @Override public void run() { while (true) { System.out.println("hello,world " + (++count) + " "+Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 10) { break; } } }}class T2 implements Runnable { int count = 0; @Override public void run() { while (true) { System.out.println("hi " + (++count) + " " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 5) { break; } } }}package com.hspedu.ticket;/** * @author DL5O * @version 1.0 * 使用多线程,模拟三个窗口同时售票 * 总票数 100 张 */public class SellTicket { public static void main(String[] args) { //第一种方式 //测试 /*SellTicket01 sellTicket01 = new SellTicket01(); SellTicket01 sellTicket02 = new SellTicket01(); SellTicket01 sellTicket03 = new SellTicket01(); sellTicket01.start(); sellTicket02.start(); sellTicket03.start();*/ System.out.println("===使用接口的方式来售票==="); SellTicket02 sellTicket02 = new SellTicket02(); Thread thread1 = new Thread(sellTicket02); Thread thread2 = new Thread(sellTicket02); Thread thread3 = new Thread(sellTicket02); thread1.start();//第一个线程-窗口 thread2.start();//第二个线程-窗口 thread3.start();//第三个线程-窗口 }}//使用第一种继承thread的方式class SellTicket01 extends Thread{ private static int ticketNum = 100;//让多个线程共享 ticketNum @Override public void run() { while (true){ if (ticketNum <= 0){ System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}//实现接口的方式class SellTicket02 implements Runnable{ private int ticketNum = 100; @Override public void run() { while (true){ if (ticketNum <= 0){ System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}基本说明:
package com.hspedu.exit_;/** * @author DL5O * @version 1.0 */public class ThreadExitTest_ { public static void main(String[] args) throws InterruptedException { Test test = new Test(); test.start(); Thread.sleep(10*1000); test.setLoop(false); }}class Test extends Thread{ private boolean loop = true; private int cnt = 0; @Override public void run() { while(loop){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Test 执行中" + (++cnt)); } System.out.println("Test 运行结束"); } public boolean isLoop() { return loop; } public void setLoop(boolean loop) { this.loop = loop; } public int getCnt() { return cnt; } public void setCnt(int cnt) { this.cnt = cnt; }}
案例:
ThreadMethod01
package com.hspedu.method;/** * @author DL5O * @version 1.0 */public class ThreadMethod01 { public static void main(String[] args) throws InterruptedException { T t = new T(); 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+1)); } System.out.println(t.getName() + " 线程的优先级 = " + t.getPriority());//1 t.interrupt();//中断该线程,当执行到这里,就会中断,t线程的休眠 }}class T extends Thread {//自定义的线程类 @Override public void run() { while (true) { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " 吃包子~~~" + (i + 1)); } try { System.out.println("大龙休息中~~"); Thread.sleep(20 * 1000); } catch (InterruptedException e) { //InterruptedException 是捕获到一个终端异常 System.out.println(Thread.currentThread().getName() + "被 interrupt了"); } } }}
注意:
package com.hspedu.method;/** * @author DL5O * @version 1.0 */public class ThreadMethod02 { public static void main(String[] args) throws InterruptedException { int count = 0; Test test = new Test(); test.start(); while (true){ System.out.println("hello " + (++count)); Thread.sleep(1000); if(count == 5){ System.out.println("让test 线程先执行");// test.join();//线程插队一定会成功 Thread.yield();//线程礼让 //让test 线程先执行,执行后可以看到,当执行join后,主线程就不再执行, // 当这个test线程执行完毕后,主线程才继续执行 } if(count == 20){ break; } } }}class Test extends Thread{ private int count = 0; @Override public void run() { while(true){ System.out.println("hi " + (++count)); try { Thread.sleep( 1000);//休眠1秒 } catch (InterruptedException e) { e.printStackTrace(); } if (count == 20){ break; } } }}
package com.hspedu.method;/** * @author DL5O * @version 1.0 */public class ThreadMethodExercise { public static void main(String[] args) throws InterruptedException { T01 t01 = new T01(); for (int i = 1; i <= 10; i++) { System.out.println("hi " + i); if (i == 5) { Thread thread = new Thread(t01); thread.start(); thread.join(); System.out.println("子线程结束..."); } Thread.sleep(1000); } System.out.println("主线程结束..."); }}class T01 implements Runnable{ @Override public void run() { for (int i = 1; i <= 10 ; i++) { System.out.println("hello " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}package com.hspedu.method;/** * @author DL5O * @version 1.0 * 守护线程的设置 */public class ThreadMethod03 { public static void main(String[] args) throws InterruptedException { MyDaemonThread myDaemonThread = new MyDaemonThread(); Test01 test01 = new Test01(); myDaemonThread.setDaemon(true); //如果我们希望当main线程结束后,子线程可以自动退出 //只需将子线程设为守护线程即可 myDaemonThread.start(); test01.start(); for (int i = 1; i <= 10; i++) { System.out.println("我是主线程 " + i); Thread.sleep(1000); } }}class MyDaemonThread extends Thread { @Override public void run() { for (int i = 1; ; i++ ) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是MyDaemonThread 守护线程 " + i); } }}class Test01 extends Thread { @Override public void run() { for (int i = 1; i <= 15 ; i++ ) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是Test01 用户线程 " + i); } }}总结:
对象名.setDaemon(true)九、 线程的生命周期

线程状态转换图:

关键字:Synchronized
同步代码块
synchronized(对象){//获得对象的锁,才能操作同步代码 //需要被同步代码;}synchronized还可以放在方法声明中,表示整个方法-为同步方法
public synchronized void m(String name){ //需要被同步的代码}如何理解:
使用synchronized解决售票
package com.hspedu.syn;/** * @author DL5O * @version 1.0 * 使用多线程,模拟三个窗口同时售票 * 总票数 100 张 */public class SellTicket { public static void main(String[] args) { //第一种方式 //测试 /*SellTicket01 sellTicket01 = new SellTicket01(); SellTicket01 sellTicket02 = new SellTicket01(); SellTicket01 sellTicket03 = new SellTicket01(); sellTicket01.start(); sellTicket02.start(); sellTicket03.start();*/ /*System.out.println("===使用接口的方式来售票==="); SellTicket02 sellTicket02 = new SellTicket02(); Thread thread1 = new Thread(sellTicket02); Thread thread2 = new Thread(sellTicket02); Thread thread3 = new Thread(sellTicket02); thread1.start();//第一个线程-窗口 thread2.start();//第二个线程-窗口 thread3.start();//第三个线程-窗口*/ //测试 SellTicket03 sellTicket03 = new SellTicket03(); Thread thread1 = new Thread(sellTicket03); Thread thread2 = new Thread(sellTicket03); Thread thread3 = new Thread(sellTicket03); thread1.start();//第一个线程-窗口 thread2.start();//第二个线程-窗口 thread3.start();//第三个线程-窗口 }}//实现接口的方式,使用synchronized 实现线程同步class SellTicket03 implements Runnable { private int ticketNum = 100; private boolean loop = true; public synchronized void sell() { //同步方法,在同一个时刻只能有一个线程来执行我们的run方法 if (ticketNum <= 0) { loop = false; System.out.println("票已售空,售票结束.."); return; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票," + "剩余票数=" + (--ticketNum)); } @Override public void run() { while (loop) { sell(); } }}//使用第一种继承thread的方式class SellTicket01 extends Thread { private static int ticketNum = 100;//让多个线程共享 ticketNum @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}//实现接口的方式class SellTicket02 implements Runnable { private int ticketNum = 100; @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}基本介绍:
Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问
同步的局限性:导致程序的执行效率要降低
同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
同步方法(静态的)的锁为当前类本身。
注意事项:
package com.hspedu.syn;/** * @author DL5O * @version 1.0 * 使用多线程,模拟三个窗口同时售票 * 总票数 100 张 */public class SellTicket { public static void main(String[] args) { //第一种方式 //测试 /*SellTicket01 sellTicket01 = new SellTicket01(); SellTicket01 sellTicket02 = new SellTicket01(); SellTicket01 sellTicket03 = new SellTicket01(); sellTicket01.start(); sellTicket02.start(); sellTicket03.start();*/ /*System.out.println("===使用接口的方式来售票==="); SellTicket02 sellTicket02 = new SellTicket02(); Thread thread1 = new Thread(sellTicket02); Thread thread2 = new Thread(sellTicket02); Thread thread3 = new Thread(sellTicket02); thread1.start();//第一个线程-窗口 thread2.start();//第二个线程-窗口 thread3.start();//第三个线程-窗口*/ //测试 SellTicket03 sellTicket03 = new SellTicket03(); Thread thread1 = new Thread(sellTicket03); Thread thread2 = new Thread(sellTicket03); Thread thread3 = new Thread(sellTicket03); thread1.start();//第一个线程-窗口 thread2.start();//第二个线程-窗口 thread3.start();//第三个线程-窗口 }}//实现接口的方式,使用synchronized 实现线程同步class SellTicket03 implements Runnable { private int ticketNum = 100; private boolean loop = true; Object obj =new Object();//都是同一个对象 //同步方法(静态的) 的锁为当前类 //1.他的锁是加载我们这个类上的 SellTicket03.Class 上 //2.如果要在静态方法中实现一个同步代码块. // synchronized (SellTicket03.class) public synchronized static void m1(){ } public static void m2(){ synchronized (SellTicket03.class){ System.out.println("m2"); } } //是在方法上加的锁 //说明 //1.public synchronized void sell()就是一个同步方法 //2.这时锁是在this对象 //3.也可以在代码块上写 synchronized,同步代码块,互斥锁还是在this对象 public /*synchronized*/ void sell() {//同步方法,在同一个时刻只能有一个线程来执行我们的run方法 synchronized (/*this*/obj){ if (ticketNum <= 0) { loop = false; System.out.println("票已售空,售票结束.."); return; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票," + "剩余票数=" + (--ticketNum)); } } @Override public void run() { while (loop) { sell(); } }}//使用第一种继承thread的方式//new SellTicket01().start()//new SellTicket01().start() this只对当前的对象有效class SellTicket01 extends Thread { private static int ticketNum = 100;//让多个线程共享 ticketNum //锁一般用于共享的只有 public void m1(){ synchronized (this){ System.out.println("hello"); } } @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}//实现接口的方式class SellTicket02 implements Runnable { private int ticketNum = 100; @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("售票结束.."); break; } //休眠50毫秒 try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + "剩余票数=" + (--ticketNum)); } }}基本介绍:
多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程时一定要避免死锁的发生
package com.hspedu.syn;/** * @author DL5O * @version 1.0 * 模拟线程死锁 */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(); static Object o2 = new Object(); boolean flag; public DeadLockDemo(boolean flag){ this.flag = flag; } @Override public void run() { //1.如果flag为T,线程就会先得到/持有 o1的对象锁,然后会尝试去得到o2的对先生 // 当持有到 o2的对象锁时,才会继续往下执行 //2.如果线程A 得不到o2的对象锁,就会Blocked //3.如果flag 为 false,线程会去得到o2的对象锁, //4.如果线程B 拿不到o1的对象锁,就会block if(flag){ synchronized(o1){//对象互斥锁 System.out.println(Thread.currentThread().getName()+"进入1"); //拿到o1的锁之后会阻塞在这里,直到拿到o2的锁, // 此时第二个线程thread2进入,拿到o2的锁,进入堵塞状态,因为一直拿不到o1的锁, // o1又因为拿不到o2锁,释放不了,故成为了死锁 synchronized (o2){ System.out.println(Thread.currentThread().getName()+"进行2"); } } }else{ synchronized (o2){ //第二个线程 o1的锁已经被拿了, //这时,又想去拿o1的锁,但是o1在第36行阻塞到了,没有拿到o2的锁,没有释放,故这里也会被阻塞 //那么这时就会产生一种死锁的情况,要避免 System.out.println(Thread.currentThread().getName()+"进入3"); synchronized (o1){ System.out.println(Thread.currentThread().getName()+"进行4"); } } } }}下面操作会释放锁
下面操作不会释放锁
线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()暂停当前线程的执行,不会释放锁
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将会被挂起,该现场不会释放锁
提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用了

package com.hspedu.homework;import java.util.Random;import java.util.Scanner;/** * @author DL5O * @version 1.0 */public class Homework01 { public static void main(String[] args) { A a = new A(); B b = new B(a); a.setName("A"); b.setName("B");// a.setDaemon(true); a.start(); b.start(); }}class A extends Thread { private int num; static boolean loop = true; private Random random; public A() { random = new Random(); } public void showNum() { //nextInt(int bound) //返回伪随机的,均匀分布 int值介于0(含)和指定值(不包括),从该随机数生成器的序列绘制。 num = random.nextInt(101);//生成0~100的随机数 //num = (int)Math.random()*(100-0+1)+0; System.out.println("随机数:" + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { while (loop){ showNum(); } }}//用来控制A线程退出的线程Bclass B extends Thread { private String str; private A a; Scanner scanner; public B(A a) { this.a = a; scanner = new Scanner(System.in); } @Override public void run() { synchronized (B.class) { while (true) { str = scanner.next(); if (str.equals("Q")) { a.loop = false; break; } } } }}
package com.hspedu.homework;/** * @author DL5O * @version 1.0 */public class Homework02 { public static void main(String[] args) { Withdraw withdraw = new Withdraw(); Thread A = new Thread(withdraw); Thread B = new Thread(withdraw); A.setName("A"); B.setName("B"); A.start(); B.start(); }}class Withdraw implements Runnable { private int money = 10000; private boolean loop = true; public void deal() { //1.这里使用了synchronized 实现了线程同步 //2.当多个线程执行到这里的时候,就回去争夺 this对象锁 //3.那个线程执行到 this对象锁,就执行这个代码块,执行玩后,会释放这个锁,准备继续争夺 //4.争夺不到就阻塞到这里,就blocked //5.this 是一个非公平锁 synchronized (/*Withdraw.class*/this){ if (money <= 0) { loop = false; System.out.println("余额不足"); return; } money -= 1000; System.out.println(Thread.currentThread().getName() + "取走了1000,剩余" + money); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { while (loop) { deal(); } }}