一、线程介绍
1.1 程序
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/78ef696a2ca24b69aa007a60822432b5.png)
1.2 进程
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/404d0c99c55e4b7ca395ac7ba3668e8f.png)
1.3 线程
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/84cedd75b49d4eeca13a78ae1a71f18c.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/73330357a4f344b9865eb3b5832cf287.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b9f81cf7a3264af2866d90b2f3587977.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7a6484e99cfc47a1bc6676dd7c416b6a.png)
二、线程使用
2.1 创建线程的两种方式
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4489c702c5ea4e61b338bf8337b2e422.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5ca0f7be69ae4f0fa9fc14daf3f93d10.png)
2.2 继承Thread类创建线程
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a8fedc8212034555be26dbb335d787fc.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d365acb14676498d8e4deb8d637c2dcc.png)
package com.gyh.thread;
public class Thread1 {
public static void main(String[] args) throws InterruptedException {
Cat cat = new Cat();
cat.start();
System.out.println("主线程继续执行" + Thread.currentThread().getName());
for (int i = 0; i < 60; i++) {
System.out.println("主线程 i=" + i);
Thread.sleep(1000);
}
}
}
class Cat extends Thread {
@Override
public void run() {
int n = 0;
while (true) {
System.out.println("喵喵,我是小猫咪" + (++n) + "线程名" + Thread.currentThread().getName());
if (n == 80) break;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.3 实现Runnable接口创建线程
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/71841a8f4ce640d8a89f7f746e07e89e.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fcc97d62f5cd433db31e6c22b4671870.png)
package com.gyh.thread;
public class Thread2 {
public static void main(String[] args) {
Dog dog = new Dog();
Thread thread = new Thread(dog);
thread.start();
}
}
class ThreadProxy implements Runnable {
private Runnable target;
@Override
public void run() {
if (target != null) target.run();
}
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start() {
start0();
}
public void start0() {
run();
}
}
class Dog implements Runnable {
@Override
public void run() {
int count = 0;
while (true) {
System.out.println("小狗汪汪..hi" + (++count) + "Thread name:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.4 多线程执行
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/07b4953242724e778da7de45a6f5f35f.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/22e1097bd8aa4910bc47885eb8e51db4.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5ed9088f50974023a1b5a4269474a53f.png)
package com.gyh.thread;
public class Thread3 {
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
Thread02 thread02 = new Thread02();
thread01.start();
thread02.start();
}
}
class Thread01 extends Thread {
@Override
public void run() {
int count = 0;
while (count < 10) {
System.out.println("hello,world" + (++count) + "线程名:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Thread02 extends Thread {
@Override
public void run() {
int count = 0;
while (count < 5) {
System.out.println("hi" + (++count) + "线程名:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.5 继承Thread vs 实现 Runnable的区别
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/142accc255a24df399b1671395fec111.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6c0d7c28ece54931ad2993dea0e17aea.png)
package com.gyh.thread;
public class Thread4 {
public static void main(String[] args) {
SellTicket2 sellTicket2 = new SellTicket2();
new Thread(sellTicket2).start();
new Thread(sellTicket2).start();
new Thread(sellTicket2).start();
}
}
class SellTicket01 extends Thread {
public static int ticketNum = 100;
@Override
public void run() {
while (true) {
if (ticketNum <= 0) {
System.out.println("售票结束");
break;
}
try {
Thread.sleep(50);
ticketNum--;
System.out.println("还剩" + ticketNum + "张票");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SellTicket2 implements Runnable {
private static int ticketNum = 100;
@Override
public void run() {
while (true) {
if (ticketNum <= 0) {
System.out.println("售票结束");
break;
}
try {
Thread.sleep(50);
ticketNum--;
System.out.println("还剩" + ticketNum + "张票");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.6 线程终止
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/41cbb65bdf1940428b473072b5c57a43.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/75357e004c174268bfdeb0031b5ab402.png)
package com.gyh.thread;
public class Thread5 {
public static void main(String[] args) {
T t1 = new T();
t1.start();
try {
System.out.println("主线程休眠10s");
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.setLoop(false);
}
}
class T extends Thread {
private int count = 0;
private boolean loop = true;
@Override
public void run() {
while (loop) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T 运行中....");
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
三、线程方法
3.1 常用方法
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4a40ed920c984a7ba7199b7977eb8b1a.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f5c0c9d8b8bf41f8b297b6179fbd233d.png)
package com.gyh.thread;
public class ThreadMethod {
public static void main(String[] args) throws InterruptedException {
T1 t = new T1();
t.setName("老韩");
t.setPriority(Thread.MIN_PRIORITY);
t.start();
System.out.println(t.getPriority());
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
System.out.println("hi " + i);
}
t.interrupt();
}
}
class T1 extends Thread {
@Override
public void run() {
while (true) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "吃包子~~~~" + i);
}
try {
System.out.println(Thread.currentThread().getName() + "休眠中~~~");
Thread.sleep(20000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "被 interrupt了");
}
}
}
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/ce7002134f4441a5924a3ba844b10ea1.png)
package com.gyh.thread;
public class Thread6 {
public static void main(String[] args) throws InterruptedException {
SubThread subThread = new SubThread();
subThread.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + ":hi");
Thread.sleep(1000);
if (i == 4) subThread.join();
}
}
}
class SubThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.2 用户线程和守护线程
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e1fae626033d40899d76145bda24c39c.png)
package com.gyh.thread;
public class Thread7 {
public static void main(String[] args) throws InterruptedException {
ProtectSubThread protectSubThread = new ProtectSubThread();
protectSubThread.setDaemon(true);
protectSubThread.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":hi " + i);
Thread.sleep(1000);
}
}
}
class ProtectSubThread extends Thread {
@Override
public void run() {
while (true) {
try {
System.out.println(Thread.currentThread().getName() + ":hello");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
四、线程生命周期
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f5e0c40d273d459ba04fda8cac6d7765.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b91d43dbec954e5781a49e638cde2c40.png)
package com.gyh.thread;
public class Thread8 {
public static void main(String[] args) throws InterruptedException {
Runnable t = new Runnable() {
@Override
public 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();
}
}
break;
}
}
};
Thread thread = new Thread(t);
System.out.println(thread.getName() + " 状态 " + thread.getState());
thread.start();
while (Thread.State.TERMINATED != thread.getState()) {
System.out.println(thread.getName() + " 状态 " + thread.getState());
Thread.sleep(500);
}
System.out.println(thread.getName() + " 状态 " + thread.getState());
}
}
五、Synchronized
5.1 线程同步机制
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/616f34b1318c466883d7b2d3afbb09ef.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/38d880c4f7d048ec89a4b7a1fbd9de16.png)
package com.gyh.thread;
public class Thread9 {
public static void main(String[] args) {
SubSellTicket subSellTicket = new SubSellTicket();
new Thread(subSellTicket).start();
new Thread(subSellTicket).start();
new Thread(subSellTicket).start();
}
}
class SubSellTicket implements Runnable {
private static int ticketNum = 100;
private boolean loop = true;
public synchronized void sell() {
if (ticketNum <= 0) {
System.out.println("售票结束");
return;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (--ticketNum == 0) loop = false;
System.out.println(Thread.currentThread().getName() + "通报,还剩" + ticketNum + "张票");
}
@Override
public void run() {
while (loop) {
sell();
}
}
}
5.2 同步的原理
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/3d48ff9ea02a40128f806c09d67233ca.png)
六、互斥锁
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1d2a97c5ed7749018c46ebbfb8ddf660.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/08981657cc514396abe50702243a67f4.png)
package com.gyh.thread;
public class Thread9 {
public static void main(String[] args) {
SubSellTicket subSellTicket = new SubSellTicket();
new Thread(subSellTicket).start();
new Thread(subSellTicket).start();
new Thread(subSellTicket).start();
}
}
class SubSellTicket implements Runnable {
private static int ticketNum = 100;
private boolean loop = true;
private final Object o = new Object();
public synchronized static void m1(){
}
public static void m2(){
synchronized (SubSellTicket.class){
System.out.println("m2");
}
}
public void sell() {
synchronized ( o) {
if (ticketNum <= 0) {
System.out.println("售票结束");
return;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (--ticketNum == 0) loop = false;
System.out.println(Thread.currentThread().getName() + "通报,还剩" + ticketNum + "张票");
}
}
@Override
public void run() {
while (loop) {
sell();
}
}
}
七、死锁
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/95c9066976f04845ac5c70082815afe8.png)
package com.gyh.thread;
public class Thread11 {
public static void main(String[] args) {
DeadLockDemo deadLockDemo1 = new DeadLockDemo(true);
DeadLockDemo deadLockDemo2 = new DeadLockDemo(false);
deadLockDemo1.start();
deadLockDemo2.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() {
if (flag) {
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "进入2");
}
}
} else {
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "进入3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入4");
}
}
}
}
}
九、释放锁
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/790bd80f757748a092b71144bba59fc9.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/cf9b42c2f52541dea0af881bc496fa9b.png)
八、细节
8.1 互斥锁实现同步的机制
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1de80b71b1a9456f9b82dbd785adb07a.png)
synchronized
方法可以使用this
对象的内部锁
(互斥锁
)来管理当前的方法,同一时刻该互斥锁
控制只能有一个线程能够执行synchronized
方法,因此该线程能执行代码,而其他线程由于访问不到该互斥锁
因此被阻塞
,待该互斥锁
被释放后再次争夺互斥锁
的访问权
8.2 使用继承Thread
类的方式创建线程的互斥锁的问题
- 由于继承
Thread
类的创建线程的方式,有多少个线程就会创建多少个对象,因此默认的同步方法对 this
上锁是不同的对象,不能实现同步
package com.gyh.thread;
public class Thread10 {
public static void main(String[] args) {
new SubSellTicket1().start();
new SubSellTicket1().start();
new SubSellTicket1().start();
}
}
class SubSellTicket1 extends Thread {
private static int ticketNum = 100;
private boolean loop = true;
public void sell() {
synchronized (this) {
if (ticketNum <= 0) {
System.out.println("售票结束");
return;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (--ticketNum == 0) loop = false;
System.out.println(Thread.currentThread().getName() + "通报,还剩" + ticketNum + "张票");
}
}
@Override
public void run() {
while (loop) {
sell();
}
}
}