多线程
- 一个进程包含多个线程
- 程序是一个静态的概念,当程序运行起来,cpu分配内存和资源,即进程。
- 多个线程由调度器(cpu)安排调度,所以其先后顺序是不能干预
线程的创建
-
继承Thread
/** * 测试线程安全 * 原子性 * 可见性 * 有序性 * @author * */ public class Test03 { private static int count; private static class Thread1 extends Thread{ @Override public void run() { for(int i=0;i<=1000;i++){ count++; try { Thread.sleep(1); } catch (Exception e) { // TODO: handle exception } } } } public static void main(String[] args) throws InterruptedException { Thread1 thread1=new Thread1(); Thread1 thread2=new Thread1(); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(count); } }
-
实现接口Runnable
public class Test04 implements Runnable { private static int count1; public Test04 (int i){ count1=i; System.out.println("线程"+i+"启动"); } @Override public void run() { for(int i=1;i<3;i++){ System.out.println("执行线程"+i); } try { Thread.sleep((int)Math.random()*1000); } catch (Exception e) { } } public static void main(String[] args) { Thread t1=new Thread(new Test04(1)); t1.start(); Thread t2=new Thread(new Test04(2)); t2.start(); } }
-
实现接口Callable
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 实现callable接口
* @author
*
*/
public class Test06 implements Callable<Boolean>{
@Override
public Boolean call() throws Exception {
for(int i=1;i<=20;i++){
System.out.println("执行线程"+i);
}
return true;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Test06 t1=new Test06();
Test06 t2=new Test06();
Test06 t3=new Test06();
//创建执行服务
ExecutorService ser=Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1=ser.submit(t1);
Future<Boolean> r2=ser.submit(t2);
Future<Boolean> r3=ser.submit(t3);
//获取结果
boolean rs1=r1.get();
boolean rs2=r2.get();
boolean rs3=r3.get();
//关闭服务
ser.shutdownNow();
}
}
静态代理模式
-
总结
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色,即传递一个真实对象给代理对象
-
好处
-
代理对象可以做很多真实对象做不了的事情,做真实对象之外的事情
-
真实对象专注做自己的事情
/** * 静态代理 staticProxy * @author * */ public class Test07 { public static void main(String[] args) { WeddingCompany weddingCompany=new WeddingCompany(new You()); weddingCompany.mappyMarry(); } } interface Marry{ void mappyMarry(); } class You implements Marry{ @Override public void mappyMarry() { System.out.println("结婚了,好开心"); } } class WeddingCompany implements Marry{ private You target; public WeddingCompany(You target) { this.target=target; } @Override public void mappyMarry() { before(); target.mappyMarry(); after(); } void before(){ System.out.println("结婚前,布置场地"); } void after(){ System.out.println("结婚后,收尾款"); } }
-
Lamda表达式
作用:
- 避免匿名内部类定义过多
- 属于函数式编程
函数式接口定义:
- 任何接口,如果只包含一个抽象方法,则称为函数式接口
- 使用lambda表达式简化
总结:
- lambda表达式只有一行代码的情况下,如果有多行,那么就用代码块包裹
- 前提是接口为函数式接口
- 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
/**
* lambda表达式:jdk1.8之后
* @author
*
*/
public class Test08 {
//2.定义一个静态内部类
static class Like2 implements ILike{
@Override
public void love(int a, int b) {
System.out.println("i love you->"+a);
System.out.println("i love you->"+b);
}
}
public static void main(String[] args) {
//3.定义一个内部类
class Like3 implements ILike{
@Override
public void love(int a, int b) {
System.out.println("i love you->"+a);
System.out.println("i love you->"+b);
}
}
ILike like=new Like();
like.love(1, 2);
ILike like2=new Like2();
like2.love(3, 4);
ILike like3=new Like3();
like3.love(5, 6);
//4.定义一个匿名内部类
ILike like4=new ILike() {
@Override
public void love(int a, int b) {
System.out.println("i love you->"+a);
System.out.println("i love you->"+b);
}
};
like4.love(7, 8);
//使用lambda表达式
ILike like5=(a,b)->System.out.println("i love you->"+a);
like5.love(9, 10);
}
}
//定义一个函数式接口:只有一个抽象方法
interface ILike{
void love(int a,int b);
}
//1.定义一个类实现接口
class Like implements ILike{
@Override
public void love(int a, int b) {
System.out.println("i love you->"+a);
System.out.println("i love you->"+b);
}
}
线程状态
五大状态
- 创建状态
- 就绪状态
- 阻塞状态
- 运行状态
- 死亡状态
停止线程
- 不推荐使用stop()和destory()方法
- 推荐线程自己停下来
- 使用标志位停止线程
/**
* 线程停止
* 1、建议使用标志位停止线程
* 2、不推荐使用jdk的stop和destory方法
* 3、使线程自动停止下来更加安全
* @author
*
*/
public class Test09 implements Runnable {
private static boolean flag=true;
public static void main(String[] args) {
new Thread(new Test09()).start();
for (int i = 0; i < 1000; i++) {
if(i==900){
flag=false;
System.out.println("停止线程");
}
System.out.println("主线程----"+i);
}
}
@Override
public void run() {
int i=1;
while(flag){
System.out.println("运行线程----"+i++);
}
}
}
线程休眠
Thread.sleep();
线程休眠案例:
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 线程休眠
* 1、模拟延时
* 2、倒计时
* 3、获取当前时间
* @author
*
*/
public class Test10 {
public static void main(String[] args) {
// tendDown();
Date starTime=new Date(System.currentTimeMillis());
while(true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(starTime));
starTime=new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void tendDown(){
int num=10;
while(true){
try {
Thread.sleep(1000);
System.out.println(num--);
if(num<=0){
break;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程礼让
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 让运行状态转变为就绪状态
- 礼让不一定成功,看cpu心情:让正在运行的线程重新与就绪进程竞争
/**
*
* @author 线程礼让YieId
*
*/
public class Test11 {
public static void main(String[] args) {
new Thread(new YieId(),"a").start();
new Thread(new YieId(),"b").start();
}
}
class YieId implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束执行");
}
}
线程强制执行
Join:可理解为插队,优先执行插入线程,执行完成后再执行主线程
/**
* 线程强制执行join
* @author
*
*/
public class Test12 implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread thread1=new Thread(new Test12());
thread1.start();
for (int i = 0; i <1000; i++) {
if(i==500){
thread1.join();
}
System.out.println("main执行"+i);
}
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("线程执行--"+i);
}
}
}
观察线程状态
使用Thread.State state=t1.getState();—>获取当前进程的状态
/**
*
* @author 线程状态的观测:State
*
*/
public class Test13{
public static void main(String[] args) {
Thread t1= new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("线程执行结束");
});
Thread.State state=t1.getState();
System.out.println(state);
t1.start();
state=t1.getState();
System.out.println(state);
//监测线程状态
while(state!=Thread.State.TERMINATED){
try {
Thread.sleep(200);//每隔200ms监测一次
state=t1.getState();
System.out.println(state);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程的优先级
- 使用getPriority .setPriority(int xxx)改变线程优先级(1-10)
public class Test14 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority p1=new MyPriority();
MyPriority p2=new MyPriority();
MyPriority p3=new MyPriority();
Thread t1= new Thread(p1,"p1");
Thread t2= new Thread(p2,"p2");
Thread t3= new Thread(p3,"p3");
t1.setPriority(10);
t1.start();
t2.setPriority(1);
t2.start();
t3.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
- 获取当前线程的名称Thread.currentThread.getName();
- 获取当前线程的优先级Thread.currentThread.getPriority();
- 设置线程优先级应该在线程启动之前
- 主线程的优先级不可改变
- 默认优先级为5
守护线程
daemon
- 线程分为用户线程和后台线程
- 虚拟机必须保护用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如后台记录操作日志、垃圾回收线程(gc线程)
线程同步
并发:多个线程操作同一个资源
-
线程同步是一种等待机制
-
队列和锁
-
锁机制:synchronized:当一个线程获得对象的排它锁,独占资源,其他线程必须等待
-
弊端:
- 一个线程持有锁对导致其他需要此锁的线程挂起
- 会降低性能
- 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
线程同步安全
-
不安全的买票
public class Test15 { public static void main(String[] args) { BuyTicket station=new BuyTicket(); new Thread(station,"小明").start(); new Thread(station,"小红").start(); new Thread(station,"小黄").start(); } } class BuyTicket implements Runnable{ private int tickets=10; private boolean flag=true; @Override public void run() { while(flag){ buy(); } } public void buy(){ if(tickets<=0){ flag=false; return; } try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"买到了"+tickets--); } }
-
不安全银行取钱
public class Test16 { public static void main(String[] args) { Account account=new Account("基金", 100); Drawing you=new Drawing(account, 50, "xxx"); Drawing she=new Drawing(account, 100, "yyy"); you.start(); she.start(); } } //创建一个账户 class Account{ public String name; public int money; public Account(String name,int money){ this.name=name; this.money=money; } } class Drawing extends Thread{ private Account account; private int drawingMoney; private int nowMoney; public Drawing(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("账号余额不足"); return; } try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } account.money=account.money-drawingMoney; nowMoney=nowMoney+drawingMoney; System.out.println(account.name+"的钱:"+account.money); System.out.println(this.getName()+"手里的钱:"+nowMoney); } }
-
不安全的线程集合
import java.util.ArrayList; import java.util.List; /** * 线程不安全的集合 * @author * */ public class Test17 { public static void main(String[] args) { List<String> threadList=new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ threadList.add(Thread.currentThread().getName()); }).start(); } System.out.println(threadList.size()); } }
同步方法
- public synchronized void xxx(){};
- synchronized默认锁的是this
同步块
- synchronized (Obj){}
- Obj称之为同步监视器
- JUC:CopyOnWriteArrayList list =new CopyOnWriteArrayList();本身就是线程安全的
死锁
条件
- 互斥条件
- 请求与保持条件
- 不剥夺条件
- 循环等待
Lock锁
-
同步锁使用Lock对象
-
接口Lock,其实现类ReentrantLock
-
Lock是显式锁,需要手动开启和关闭锁
-
Lock只能对代码块加锁,synchronized即可代码块和方法
线程协作
wait()等待,会释放锁
notify()唤醒
线程池
//创建线程池
ExecutorService service=Executors.newFixdThreadPool(线程池大小);
//对于Runable接口,使用execute执行,没有返回类型,只执行
//new MyThread()指实现Runnable接口的类,不需要使用静态代理
service.execute(new MyThread());
//对于callable接口,使用submit执行,使用Futrue接收
Futrue<返回类型> result=service.submit();
//获取返回值
类型 r1=result.get();
//关闭线程池
service.shutDownNow();