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