线程相关概念
· 程序
是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码
· 进程
1.是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。
2.进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的--产生--存在--消亡的过程。
· 线程
1.线程由进程创建,是进程的一个实体
2.一个进程可以拥有多个线程
单线程 :同一个时刻,只允许执行一个线程
多线程:同一个时刻,允许执行多个线程
线程基本使用案例1
package Threaduse;
public class Thread_01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();
}
}
class Cat extends Thread {
int times = 0;
int i = 0;
@Override
public void run() {
while (true) {
System.out.println("小猫喵喵叫" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
if (i == 10) {
break;
}
}
}
}
线程应用案例1 - 继承Thread类
ava 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
package Threaduse;
public class Thread_01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();
for (int i = 0; i <20 ; i++) {
System.out.println("主线程" + Thread.currentThread().getName() + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class Cat extends Thread {
int times = 0;
int i = 0;
@Override
public void run() {
while (true) {
System.out.println("小猫喵喵叫" + Thread.currentThread().getName() + i );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
if (i == 80) {
break;
}
}
}
}
jconsle查看线程状况
main和Thread - 0交替运行
main线程结束 ,Thread - 0继续运行
Thread - 0 线程结束
程序结束
线程应用案例2-实现Runnable接口
package Threaduse;
import com.polymorphic_多态.example.多态的应用.Perosn;
import jdk.nashorn.internal.ir.IfNode;
//通过实现接口Runnable 来开发线程
public class Thread_02 {
public static void main(String[] args) {
int i = 0;
Tiger tiger = new Tiger();
Thread thread = new Thread(tiger);
thread.start();
while (true) {
System.out.println("小猫喵喵叫" + i++ + " " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (i == 20) {
break;
}
}
}
}
class Animal {
}
class Tiger extends Animal implements Runnable { //java为单继承,故采用implements Runnable实现多线程运行
@Override
public void run() {
int count = 0;
while (true) {
System.out.println("老虎嗷嗷叫 " + count++ + " " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 100) {
break;
}
}
}
}
//线程代理类 ,模拟一个极简的Thread类 静态代理模式
class ThreadProxy implements Runnable {
private Runnable target = null;
@Override
public void run() {
if (target != null) {
target.run();
}
}
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start() {
start0(); //这个方法是真正实现多线程的方法
}
public void start0() {
run();
}
}
线程应用案例3 - 多线程执行
package Threaduse;
public class Thread_03 {
public static void main(String[] args) {
Hello_Cat helloCat = new Hello_Cat();
Hello_Dog helloDog = new Hello_Dog();
Hello_Bird helloBird = new Hello_Bird();
new Thread(helloCat).start();
new Thread(helloDog).start();
new Thread(helloBird).start();
}
}
class Hello_Cat implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "小猫喵喵叫" + count++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 50) {
break;
}
}
}
}
class Hello_Dog implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "小狗旺旺叫" + count++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 50) {
break;
}
}
}
}
class Hello_Bird implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "小鸟吱吱叫" + count++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 50) {
break;
}
}
}
}
继承Thread vs 实现Runnable的区别
1、从java的设计来看,通过继承Thread 和Runnable接口来创建本质没有区别
2、实现Runable接口方式更加适合多个线程共享资源的情况,并且避免了单继承的限制,建议使用Runnable
线程应用案例4 - 多线程售票(待解决超售问题) Synchroized
package Threaduse;
public class SellTicket {
public static void main(String[] args) {
// TicketsWindows01 tsw1= new TicketsWindows01();
// new Thread(tsw1).start();
// new Thread(tsw1).start();
// new Thread(tsw1).start();
TicketsWindows02 tsw2 = new TicketsWindows02();
TicketsWindows02 tsw3 = new TicketsWindows02();
TicketsWindows02 tsw4 = new TicketsWindows02();
tsw2.start();
tsw3.start();
tsw4.start();
}
}
//实现Runnable售票
class TicketsWindows01 implements Runnable {
private int i = 100;
@Override
public void run() {
while (true) {
if (i <= 0) {
System.out.println("售票结束...");
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("窗口" + Thread.currentThread().getName() + "剩余票数" + (--i));
}
}
}
class TicketsWindows02 extends Thread{
static int ticket = 100;
@Override
public void run() {
while (true){
if (ticket<=0){
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("窗口" + Thread.currentThread().getName() + "剩余票数" + (--ticket));
}
}
}
线程应用案例5-通知线程退出(线程终止)
package Threaduse.exit;
public class ThreadExit {
public static void main(String[] args) {
T t1 = new T();
t1.start();
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t1.setLoop(false);
}
}
class T extends Thread{
private int count = 0;
private boolean loop =true;
public void setLoop(boolean loop) {
this.loop = loop;
}
@Override
public void run() {
while (loop){
System.out.println("T运行中" + count ++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
通过 main函数中 t1.setLoop(false);控制线程内循环的条件,结束循环-->结束进程
线程常用方法
package com.method;
public class ThreadMethod01 {
public static void main(String[] args) {
T t = new T();
t.setPriority(Thread.MIN_PRIORITY);
t.start();
t.setName("----老韩---- ");
while (true) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("hi");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(t.getPriority());
t.interrupt();
}
}
}
class T extends Thread {
@Override
public void run() {
while (true) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "老韩正在吃包子中" + i);
}
try {
System.out.println(Thread.currentThread().getName() + "休眠中");
Thread.sleep(1000 * 20);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "线程被中断了");
}
}
}
}
线程的插队
package com.method;
public class ThreadMethod02 {
public static void main(String[] args) throws InterruptedException {
T2 t2 = new T2();
t2.start();
int count = 0;
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "打工人在吃包子" + i);
count ++;
Thread.sleep(1000);
if (count == 5) {
t2.join();//子线程插队
}
}
}
}
class T2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "老板在吃包子" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
线程常用方法练习
package com.method;
public class ThreadMethodExercise {
public static void main(String[] args) throws InterruptedException {
T3 t3 = new T3();
Thread thread = new Thread(t3);
for (int i = 1; i < 11 ; i++) {
System.out.println(Thread.currentThread().getName() + " hi " + i );
Thread.sleep(1000);
if (i == 5){
thread.start();
thread.join();
}
}
}
}
class T3 implements Runnable{
@Override
public void run() {
for (int i = 1; i <11 ; i++) {
System.out.println(Thread.currentThread().getName() + " hello " + i );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
用户线程和守护线程
package com.method;
public class ThreadMethod03 {
public static void main(String[] args) throws InterruptedException {
T4 t4 = new T4();
t4.setDaemon(true); //打开守护线程,main进程结束,子进程也结束
t4.start();
for (int i = 0; i < 10; i++) {
System.out.println("HELLO" + i);
Thread.sleep(1000);
}
}
}
class T4 extends Thread{
@Override
public void run() {
for (;;){
System.out.println("hi");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
线程的生命周期
package com.method;
public class Thread_State {
public static void main(String[] args) {
T5 t5 = new T5();
t5.start();
System.out.println(t5.getName() + t5.getState());
while(Thread.currentThread().getName() != t5.getName()){
System.out.println(t5.getName() + t5.getState());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(t5.getName() + t5.getState());
}
}
class T5 extends Thread {
int count = 0;
@Override
public void run() {
while (true) {
count++;
System.out.println(Thread.currentThread().getName() + " ---HELLO ---" + count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 5) {
break;
}
}
}
}
线程同步机制
package com.hspedu.syn;
/**
* @author 韩顺平
* @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();
//
// new Thread(sellTicket02).start();//第1个线程-窗口
// new Thread(sellTicket02).start();//第2个线程-窗口
// new Thread(sellTicket02).start();//第3个线程-窗口
//测试一把
SellTicket03 sellTicket03 = new SellTicket03();
new Thread(sellTicket03).start();//第1个线程-窗口
new Thread(sellTicket03).start();//第2个线程-窗口
new Thread(sellTicket03).start();//第3个线程-窗口
}
}
//实现接口方式, 使用synchronized实现线程同步
class SellTicket03 implements Runnable {
private int ticketNum = 100;//让多个线程共享 ticketNum
private 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(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
+ " 剩余票数=" + (--ticketNum));//1 - 0 - -1 - -2
}
}
@Override
public void run() {
while (loop) {
sell();//sell方法是一共同步方法
}
}
}
//使用Thread方式
// new SellTicket01().start()
// new SellTicket01().start();
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;//让多个线程共享 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));//1 - 0 - -1 - -2
}
}
}
互斥锁
同步具体方法-Synchronized
非静态方法的锁
静态方法的锁,锁加在类本身上
这段代码无法锁住,对象不共享,不是同一个对象
线程死锁
package com.hspedu.syn;
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 {
boolean flag ;
static Object o1 = new Object();
static Object o2 = new Object();
public DeadLockDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
//1、如果flag为真,线程A就会得到/持有o1对象锁,然后尝试去获取o2对象锁
//2、如果线程A得不到o2对象锁,就会block
//3、如果flag为假,线程B就会得到/持有o2对象锁,然后尝试去获取o1对象锁
//4、如果线程B德不到o1对象锁,就会block
if (flag) {
synchronized (o1) {//对象互斥锁,下面是同步代码
System.out.println(Thread.currentThread().getName() + " 进入1");
synchronized (o2) {//这里获得li对象监视权
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");
}
}
}
}
}
释放锁
多线程练习题一
package com.ThreadHomework;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import java.util.Scanner;
public class Homework01 {
public static void main(String[] args) {
A a = new A();
a.start();
B b = new B(a);
b.start();
}
}
class A extends Thread {
boolean loop = true;
@Override
public void run() {
while (loop) {
Random r = new Random();
System.out.println(r.nextInt(100));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
class B extends Thread {
private A a;
private Scanner scanner = new Scanner(System.in);
public B(A a) {//构造器中,直接传入A类对象,从而控制A
this.a = a;
}
@Override
public void run() {
while (true) {
System.out.println("请输入你的指令Q");
char key = scanner.next().toUpperCase().charAt(0);
if (key =='Q' ){
a.setLoop(false);
System.out.println("输入了Q退出");
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
多线程练习题二
package com.ThreadHomework;
import com.polymorphic_多态.example.转型.Cat;
public class Hoemwork02 {
public static void main(String[] args) {
Money money = new Money();
Thread thread01 = new Thread(money);
Thread thread02 = new Thread(money);
thread01.setName("用户1");
thread01.start();
thread02.setName("用户2");
thread02.start();
}
}
//涉及到多个线程共享资源的方式,使用Runnable的方式
class Money implements Runnable {
private int cash = 10000;
@Override
public void run() {
while (true) {
//1.这里使用 实现了线程同步
//2.当多个线程执行到这里时,就会争夺this对象锁
//3.哪个线程争夺到(获取)到this对象的锁,就执行synchronized 代码块,执行完后,会释放this对象锁
//4.争夺不到this对象锁,就blocked,准备继续争夺
//5.this对象锁是非公平锁
synchronized (this) {
if (cash > 0) {
System.out.println(Thread.currentThread().getName() + "取出了1000元" + (cash = cash - 1000));
} else if (cash <= 0) {
System.out.println(Thread.currentThread().getName() + "钱已取完了");
break;
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}