线程的创立形式
继承Thread
继承Therad类,并重写run()办法
public class T1 extends Thread{
@Override public void run(){ } public static void main(String[] str){ T1 t1=new T1(); t1.start(); }
}
实现Runnable
实现Runnable,并重写run()办法,调用时应用Therad包裹
public class T1 implements Runnable{
@Override public void run(){ } public static void main(String[] str){ T1 t1=new T1(); Thread t2=new Thread(t1); t2.start(); }
}
lambda 简化
new Thread(
()->{}
).start();
线程的五大状态
image.png
状态 形容
创立状态 new进去的时候就是创立状态
就绪状态 调用是start() 就是就绪状态
运行状态 就绪状态失去cpu的调度,进入运行状态
阻塞状态 线程运行暂停,就是阻塞状态,例如调用sleep(),阻塞状态之后会进入就绪状态
死亡状态 线程执行结束或被终止
线程的操作
线程的进行
JDK提供的Stop(),destroy()都已废除,不倡议用
倡议应用一个标记位进行终止变量,或等线程本人进行
public class T1 implements Runnable{
private Boolean f=true; @Override public void run(){ int a=0; while(f){ System.out.println(a++); } } public void stop(){ f=false; } public static void main(String[] str){ T1 t1=new T1(); Thread t2=new Thread(t1); t2.start(); for (int a=0;a<1000;a++){ if (a==900){ t1.stop(); } } }
}
线程的休眠 sleep()
sleep指定线程阻塞的毫秒数,毫秒即千分之一秒
sleep存在异样
sleep执行实现后进入就绪状态
sleep不会开释锁
new Thread(()->{
try { int a=10; while(a>=0){ Thread.sleep(1000); System.out.println(a--); } } catch (InterruptedException e) { e.printStackTrace(); } }).start();
线程礼让 yield()
将执行的线程暂停但不阻塞
将线程从运行状态转为就绪状态
礼让之后调度状态随机
Thread thread1 = new Thread(() -> {
System.out.println("线程开始"); Thread.yield(); System.out.println("线程进行"); }); Thread thread = new Thread(() -> { System.out.println("线程开始1"); Thread.yield(); System.out.println("线程进行1"); }); thread1.start(); thread.start();;
线程插队 join()
Join合并线程,当此线程执行实现后,能力执行其余线程,其余线程阻塞
public static void main(String[] args) {
Thread thread1 = new Thread(() -> { for(int i=0;i<1000;i++) { System.out.println("线程VIP"); } }); for (int i=0;i<1000;i++){ if (i==900){ try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(i); } }
守护线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行结束,不必期待守护线程执行结束
守护线程如记录日志,监控内存,垃圾回收等
并发
同一个对象被多个线程同时操作就是并发
线程同步
为了解决多个并发问题,引入锁机制synchronized ,党当一个对象取得锁,独占资源,其余线程必须期待,应用后开释锁即可
锁带来的问题
一个线程持有锁会导致其余须要此锁的线程挂起
多个线程竞争,加锁开释锁引起性能问题
高优先级线程期待低优先级呈现优先级倒置,引起性能问题
锁就是要锁变动的对象
同步办法
对于简略的不是批改其余对象的办法,能够间接应用synchronized锁定以后办法
写法就是间接在办法中增加synchronized 关键字
@Override
public synchronized void run() { while (f){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"买到"+p--); if (p<=0){ f=false; <b style="color:transparent">来源gao@dai!ma.com搞$代^码网</b> return; } } }
同步块
当线程批改了以后办法外的其余对象,就须要应用同步块
格局:
synchronized (加锁对象){
线程办法
}
例如:
@Override
public void run() { while (f){ synchronized (qian){ if (qian.getM()<=0){ f=false; break; } qian.setM(qian.getM()-yici); System.out.println("取出"+yici+"还剩"+qian.getM()); } } }
Lock锁
Lock是显式锁(手动开关),synchronization是隐式锁,出了作用域主动开释
Lock没有办法锁,只有代码块锁
Lock锁性能更好,扩展性更高
优先应用Lock,其次同步块,其次同步办法
罕用Lock锁,ReentrantLock (可重入锁)
private final ReentrantLock a=new ReentrantLock(); @Override public void run() { while (f){ try { a.lock(); if (p<=0){ f=false; return; } Thread.sleep(100); System.out.println(Thread.currentThread().getName()+"买到"+p--); } catch (InterruptedException e) { e.printStackTrace(); }finally { a.unlock(); } } }
死锁
死锁即两个或多个线程,都在期待对方开释锁,如多个同步块嵌套
产生死锁的四个必要条件
互斥条件
一个资源每次只能被一个过程应用
申请与放弃条件
线程阻塞时对已持有锁不开释
不剥夺条件
过程以取得的资源,在未应用完之前,不能强行剥夺
循环期待条件
多个过程之间闭环期待开释
线程通信
生产生产模式
管程法
即线程独特操作一个容器,生产者生产的产品放到容器的产品汇合,消费者从产品汇合中取出产品
生产者:
产品汇合满了,线程期待,期待消费者生产后唤醒生产者
没满就存入,而后唤醒消费者
消费者:
没产品了就期待,生产者生产了产品后会唤醒消费者
有产品就生产,而后唤醒生产者
public class Test6 {
public static void main(String[] args) { 容器 r=new 容器(); 生产者 s=new 生产者(r); 消费者 x=new 消费者(r); Thread ts=new Thread(s); Thread tx=new Thread(x); ts.start(); tx.start(); }
}
class 生产者 implements Runnable{
容器 r; public 生产者(容器 r) { this.r = r; } @Override public void run() { for (int a=0;a<100;a++){ r.放入(new 产品(a)); System.out.println("生产了"+a); } }
}
class 消费者 implements Runnable{
容器 r; public 消费者(容器 r) { this.r = r; } @Override public void run() { for (int a=0;a<100;a++){ System.out.println("------------取出了"+r.取出().id); } }
}
class 产品{
int id; public 产品(int id) { this.id = id; }
}
class 容器{
产品[] 产品容器=new 产品[20]; int 数量=0; public synchronized void 放入(产品 c){ try { if (数量==产品容器.length) { this.wait(); } 产品容器[数量]=c; 数量++; this.notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized 产品 取出() { try { if (数量==0){ this.wait(); } }catch (Exception e){ } 数量 --; 产品 c=产品容器[数量]; this.notifyAll(); return c; }
}
信号灯法
信号灯法就是在交互层,搁置一个标记位,如果为真,生产者操作,如果为假,消费者操作,操作完都会取反。
public class Test7 {
public static void main(String[] args) { 交互 j=new 交互(); 生产 s=new 生产(j); 生产 x=new 生产(j); Thread ts=new Thread(s); Thread tx=new Thread(x); ts.start(); tx.start(); }
}
class 生产 implements Runnable{
交互 j; public 生产(交互 j) { this.j = j; } @Override public void run() { for (int a=0;a<100;a++){ j.生产("节目---"+a); } }
}
class 生产 implements Runnable{
交互 j; public 生产(交互 j) { this.j = j; } @Override public void run() { for (int a=0;a<100;a++){ j.生产(); } }
}
class 交互{
String a=""; boolean f=true; public synchronized void 生产(String s){ if (!f){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产了"+s); this.a=s; this.notifyAll(); f=!f; } public synchronized void 生产(){ if (f){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产了"+a); this.notifyAll(); f=!f; }
}
线程池