线程的创立形式
继承 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;
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;
}
}
线程池