线程简介
Process(进程)和Thread(线程)
进程:执行程序的一次执行过程,他是一个动态概念,是系统资源分配的单位
线程就是独立的执行路径
在程序运行式,即使没有自己创建线程,后台也会有多个线程
main称之为主线程,为系统的入口,用于执行整个程序
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度是与操作系统紧密相关的,先后顺序式不能人为的干预的
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
线程会带来额外的开销,如cpu调度实践,并发控制开销
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
进程---->线程(默认线程 main线程 gc线程)
线程创建
Thread class:继承Thread类
Runnable接口:实现Runnable接口
Callable接口:实现Callable接口
继承Thread类:
子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性
实现Runnable接口
实现接口Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
实现Callable 接口
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.创建目标对象
4.创建执行服务:ExecutorService ser =Executors.newFixedThreadPool(1)
5.提交执行:Future result1=ser.submit(t1);
6.获取结果:boolean r1=result1.get();
7.关闭服务:ser.shutdownNow();
Lambda表达式
避免匿名内部类定义过多
其实质为面向函数式编程
函数式接口是学习Lambda表达式的重点
任何一个接口如果只包含唯一一个抽象方法,那么他就是一个函数式接口
多余函数式接口,我们可以使用Lambda表达式实现接口
简化过程:实体类—>静态内部类---->局部内部类---->匿名内部类---->Lambda简化
package com.kuang.demo02;
/**
* @Package: com.kuang.demo02
* @ClassName: TestLamda1
* @Author: adim
* @CreateTime: 2020/8/11 16:23
* @Description:推到Lambda表达式
*/
public class TestLamda1 {
//3.静态内部类
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
//1.定义一个函数式接口
public static void main(String[] args) {
ILike like=new Like();
like.lambda();
ILike like2=new Like2();
like2.lambda();
//4.局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like=new Like3();
like.lambda();
//5.匿名内部类,没有类的名称,必须借助接口或者父类实现
like=new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
//6.用lambda简化
like=()-> {
System.out.println("i like lambda5");
};
like.lambda();
}
}
interface ILike{
void lambda();
}
//2.实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
package com.kuang.demo02;
import java.util.List;
/**
* @Package: com.kuang.demo02
* @ClassName: TestLambda2
* @Author: adim
* @CreateTime: 2020/8/11 16:33
* @Description:
*/
public class TestLambda2 {
static class Love2 implements ILove{
@Override
public void love(int a) {
System.out.println(a);
}
}
public static void main(String[] args) {
ILove iLove=new Love();
iLove.love(1);
Love2 love2=new Love2();
love2.love(2);
ILove love3= new ILove(){
@Override
public void love(int a) {
System.out.println(a);
}
};
love3.love(3);
//lambda简化
//简化一:去除参数类型
ILove love4=(a)->{
System.out.println(a);
};
//简化括号:
love4=a->{
System.out.println(a);
};
//简化三:去除花括号
love4=a-> System.out.println("i love" +a);
//总结:若想去除花括号,代码必须只有一行,
/*
* lambda只能有一行代码的情况下,才能简化成为一行,如果有多行,那么只能由代码块包括
* 2.前提是接口为函数式接口
*3.多个参数也可以去除参数类型,但是要去掉必须同时去掉
* */
love4.love(5);
}
}
interface ILove{
void love(int a);
}
class Love implements ILove{
@Override
public void love(int a) {
System.out.println(a);
}
}
线程实现(重点)
线程五大状态
创建状态:
就绪状态
运行状态
阻塞状态
死亡状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mn6UhqBV-1597666025660)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812093024022.png)]
setPriority :
sleep:
join:
yield
isAlive
线程停止:推荐使用一个标志位进行终止变量,当flag=false,则线程终止运行
package com.kuang.state;
/**
* @Package: com.kuang.state
* @ClassName: TestTop
* @Author: adim
* @CreateTime: 2020/8/12 9:34
* @Description:建议使用线程正常停止,利用次数不建议死循环,建议使用标志位
* 2.不要使用stop或destory等过时或者JDK不建议使用的方法
*/
public class TestTop implements Runnable{
private boolean falg=true;
@Override
public void run() {
int i=0;
while(falg){
System.out.println("run ... Thread"+i++);
}
}
public void stop(){
this.falg=false;
}
public static void main(String[] args) {
TestTop testTop=new TestTop();
new Thread(testTop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i==900){
testTop.stop();
System.out.println("线程停止了");
}
}
}
}
线程休眠:
sleep(时间)指定当前线程阻塞的毫秒数
sleeep存在异常InterruptedException
sleep时间达到后线程进入就绪状态
sleep可以模拟网络延时,倒计时等
每一个对象都有一个锁,sleep不会释放锁
package com.kuang.state;
import java.beans.SimpleBeanInfo;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Package: com.kuang.state
* @ClassName: TestSleep2
* @Author: adim
* @CreateTime: 2020/8/12 9:42
* @Description:模拟倒计时,打印系统时间
*/
public class TestSleep2 {
public static void main(String[] args) {
Date startTime=new Date(System.currentTimeMillis());
while (true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime=new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//模拟倒计时
public void tenDown() throws InterruptedException {
int num=10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if(num<0){
break;
}
}
}
}
线程礼让
礼让线程,让当前正在执行的线程暂停,但不阻塞
将现场从运行状态转为就绪状态
让cpu重新调度,但是礼让可能不成功
package com.kuang.state;
/**
* @Package: com.kuang.state
* @ClassName: TestYied
* @Author: adim
* @CreateTime: 2020/8/12 9:48
* @Description:测试礼让线程,礼让不一定成功,看CPU心情
*/
public class TestYied {
public static void main(String[] args) {
MyYield myYield=new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println("开始执行"+Thread.currentThread().getName());
// Thread.yield();//礼让
System.out.println("停止执行"+Thread.currentThread().getName());
}
}
join:
join合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞
package com.kuang.state;
/**
* @Package: com.kuang.state
* @ClassName: TestJoin
* @Author: adim
* @CreateTime: 2020/8/12 10:01
* @Description:测试join方法
*/
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("vip来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin=new TestJoin();
Thread thread= new Thread(testJoin);;
thread.start();
//主线程
for (int i = 0; i < 1000; i++) {
if(i==200){
thread.join();
}
System.out.println("main"+i);
}
}
}
线程状态观测:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x3CMrdrv-1597666025664)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812100732579.png)]
package com.kuang.state;
import java.util.SortedMap;
/**
* @Package: com.kuang.state
* @ClassName: TestState
* @Author: adim
* @CreateTime: 2020/8/12 10:08
* @Description:
*/
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("");
}
});
Thread.State state = thread.getState();
System.out.println(state);
thread.start();
state=thread.getState();
System.out.println(state);
while(state!=Thread.State.TERMINATED){
Thread.sleep(1000);
state=thread.getState();
System.out.println(state);
}
}
}
线程优先级:
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
使用getPriority获取优先级,使用setProiority来修改优先级
守护线程(damon)
线程分为用户现场和守护线程
虚拟机必须保证用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如,后台级联操作日志,监控内存,垃圾回收等待。。。
package com.kuang.state;
import sun.awt.windows.ThemeReader;
/**
* @Package: com.kuang.state
* @ClassName: TestDaemon
* @Author: adim
* @CreateTime: 2020/8/12 10:45
* @Description:测试守护线程
*/
public class TestDaemon {
public static void main(String[] args) {
God god =new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true);
thread.start();//守护线程执行
new Thread(you).start();//用户现场启动
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生开心的或者");
}
System.out.println("goodbye world=====");
}
}
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("shangdibaoyouzheni");
}
}
}
线程同步(重点)
多个线程操作同一个资源
并发:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZPDAldEW-1597666025666)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812105435706.png)]
三大不安全案例
package com.kuang.syn;
import java.util.ArrayList;
import java.util.List;
/**
* @Package: com.kuang.syn
* @ClassName: UnsafeList
* @Author: adim
* @CreateTime: 2020/8/12 11:22
* @Description:线程不安全的集合
*/
public class UnsafeList {
public static void main(String[] args) {
List<String> list=new ArrayList<String>() ;
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
list.add(Thread.currentThread().getName());
}).start();
}
System.out.println(list.size());
}
}
package com.kuang.syn;
/**
* @Package: com.kuang.syn
* @ClassName: UnsafeBank
* @Author: adim
* @CreateTime: 2020/8/12 11:08
* @Description:不安全的取钱
*/
public class UnsafeBank {
public static void main(String[] args) {
Account account=new Account(100,"基金");
Bank bank=new Bank(account,60,"你");
Bank bank1=new Bank(account,60,"你的妻子");
bank.start();
bank1.start();
}
}
class Account{
int money;
String name;
public Account(int money,String name) {
this.name=name;
this.money=money;
}
}
class Bank extends Thread{
Account account;
int drawingMoney;
int nowMoney;
public Bank(Account account,int drawingMoney,String name){
super(name);
this.account=account;
this.drawingMoney=drawingMoney;
}
@Override
public void run(){
if(account.money-drawingMoney<=0){
System.out.println(Thread.currentThread().getName()+"钱不够取不了");
return;
}
//sleep可以放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money=account.money-drawingMoney;
nowMoney=drawingMoney;
System.out.println(account.name+"余额"+account.money);
System.out.println(this.getName()+"手里的钱"+nowMoney);
}
}
package com.kuang.syn;
import javax.management.relation.RoleUnresolved;
/**
* @Package: com.kuang.syn
* @ClassName: UnsafeBuyTicket
* @Author: adim
* @CreateTime: 2020/8/12 11:01
* @Description:线程不安全
*/
public class UnsafeBuyTicket {
public static void main(String[] args) {
safeBuyTicket safeBuyTicket=new safeBuyTicket();
new Thread(safeBuyTicket,"1").start();
new Thread(safeBuyTicket,"2").start();
new Thread(safeBuyTicket,"3").start();
}
}
class safeBuyTicket implements Runnable{
private int ticketNums=10;
private boolean falg=true;
@Override
public void run() {
while(falg){
buy();
}
}
public void buy(){
if(ticketNums<=0){
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--+"张票");
}
}
结局方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AmEdemWU-1597666025668)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812155354114.png)]
死锁
各个线程各自站有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,摸一个同步块同时拥有两个以上的对象的锁就会产生死锁
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nh4HRq31-1597666025670)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812165830400.png)]
线程通信问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRJ5lIGJ-1597666025671)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20200812214606326.png)]