线程--锁--死锁--wait()与sleep()方法休眠--守护线程--线程的优先级

线程

1.概念与引入

进程:操作系统上应用程序拆分成多个小任务

线程:进程拆分成对个小任务

在某个时刻,CPU的某个核中只能执行一个进程,进程可以拆分成多个线程,CPU的某个核中只能执行一个线程。CPU会轮换线程执行。

2.多线程的好处

线程要么和CPU进制交互,要么和硬件进行交互,当线程和硬件进交互时,CPU处于空闲时间。为了提高CPU利用率(理论上可以是100%)引入多线程。

3.创建多线程方式

1.继承Thread类重写run方法(线程执行任务信息),创建对象调用Thread类里start方法来开启线程

2.实现Runnable接口重写run方法(线程执行任务信息),由Runnable实现类对象来构建Thread类的对象来调用start方法开始线程(常用)

多线程之间存在相互抢占(CPU执行权—随机),抢占发生在代码的每一步,产生错误的数据问题,导致多线程数据并发安全问题

4.解决方式—加锁

1.同步代码块锁

synchronized(锁对象){}

根据锁对象共享进来的线程对象保证在执行代码块内容时不会有抢占

锁对象:一个对象,可以把哪些线程对象共享进来

可以把当前参与的线程对象共享进来的对象

方法区资源(把所有的线程对象都共享)

this(当参与的所有线程对象被Runnable实现类对象共享)

import java.io.FileInputStream;

import java.io.IOException;

import java.util.Properties;

public class SellerTicketDemo1{
public static void main(String[]args)throws IOException{
//加载配置文件
Properties p=new Properties();
p.load(new FileInputStream("ticket.properties"));
//根据键来获取值
String count=p.getProperty("count");
//创建代表票的类的对象
Ticket t= newTicket();
//设置初始票数
t.setCount(Integer.parseInt(count));
//创建代表线程执行信息的类的对象---四个售票员
Seller s1=new Seller(t);
Seller s2=new Seller(t);
Seller s3=new Seller(t);
Seller s4=new Seller(t);
//创建四个线程对象
//指定线程对象的名称
Thread t1=new Thread(s1,"A");
Thread t2=new Thread(s2,"B");
Thread t3=new Thread(s3,"C");
Thread t4=new Thread(s4,"D");
//开启线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//定义类---代表线程执行任务信息(卖票)
//代表售票员的类
class Seller implements Runnable{
//代表票数---共卖100张票
//staticintcount=100;
//声明代表票的类的对象
private Ticket t;
//有参构造---保证创建的对象共享同一个t对象
public Seller(Ticket t){
this.t=t;
}
//重写run方法---卖票过程
@Override
public void run(){
//循环实现
while(true){
//同步代码块锁
//锁对象:给定对象,可以共享哪些线程对象
//被共享进来的线程对象,在代码块内就不会相互抢占
//synchronized(t){//t--把当前参与的线程对象共享进来
//指定锁对象可以把所有的线程对象共享进来--(方法区资源)
synchronized(Math.class){//Seller.classString.class
//出循环的条件
if(t.getCount()==0)
break;
//卖一张票---设置新的剩余票数
t.setCount(t.getCount()-1);
//输出
//Thread.currentThread()---当前正在执行的线程对象
System.out.println(Thread.currentThread().getName()+
"卖了一张票,还剩余"+t.getCount()+"张票...");
//休眠
try{
Thread.sleep(10);
}catch(InterruptedException e){

e.printStackTrace();
}
}
}
}
}
//代表票的类
class Ticket{
//代表票数
private int count;
public int getCount(){
return count;
}
public void setCount(int count){
this.count=count;
}
}

2.同步方法锁

根据锁对象共享进来的线程对象保证在执行方法里内容不会有抢占锁对象

当在非静态方法上加上锁,默认锁对象就是this

当在静态方法上加上锁,默认锁对象就是当前类.class(方法区资源)

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class SellerTicketDemo2{
public static void main(String[]args)throws IOException{
//加载配置文件
Properties p=new Properties();
p.load(new FileInputStream("ticket.properties"));
//根据键来获取值
String count=p.getProperty("count");
//创建代表票的类的对象
Ticket t=new Ticket();
//设置初始票数
t.setCount(Integer.parseInt(count));
//创建代表线程执行信息的类的对象---一个售票系统
Seller1 s1=new Seller1(t);
//创建四个线程对象
//指定线程对象的名称
//四个线程对象共享同一个Runnable实现类对象
Thread t1=new Thread(s1,"A");
Thread t2=new Thread(s1,"B");
Thread t3=new Thread(s1,"C");
Thread t4=new Thread(s1,"D");
//开启线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//定义类---代表线程执行任务信息(卖票)
//代表售票员的类
class Seller1 implements Runnable{
//代表票数---共卖100张票
//staticintcount=100;
//声明代表票的类的对象
private Ticket t;
//有参构造---保证创建的对象共享同一个t对象
public Seller1(Ticket t){
this.t=t;
}
//重写run方法---卖票过程
//同步方法锁
//如果是非静态方法,默认锁对象就是this
//如果是静态方法,默认锁对象就是当前类.class(方法区资源)
@Override
public synchronized void run(){
//循环实现
while(true){
//同步代码块锁
//锁对象:给定对象,可以共享哪些线程对象
//被共享进来的线程对象,在代码块内就不会相互抢占
//synchronized(t){//t--把当前参与的线程对象共享进来
//指定锁对象可以把所有的线程对象共享进来--(方法区资源)
//synchronized(Math.class){//Seller.classString.class
//this指代成一个Runnable实现类对象
//synchronized(this){
//出循环的条件
if(t.getCount()==0)
break;
//卖一张票---设置新的剩余票数
t.setCount(t.getCount()-1);
//输出
//Thread.currentThread()---当前正在执行的线程对象
System.out.println(Thread.currentThread().getName()+
"卖了一张票,还剩余"+t.getCount()+"张票...");
//休眠
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
}

同步:在某个时刻只能由一个线程对象拥有资源(没有抢占)

异步:一个资源会被多个线程对象来抢占

同步一定是安全的,异步不一定不安全

5.死锁

由于锁的嵌套导致死锁问题,通过死锁检测来让其中一个线程对象先执行

public class DeadLockDemo{
//创建打印的扫描的对象
private static Scann s=new Scann();
private static Printer p=new Printer();
public static void main(String[]args){
//员工--先打印再扫描
Thread t1=new Thread(new Runnable(){
@Override
public void run(){
synchronized(p){
p.print();
//休眠
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
synchronized(s){
s.scan();
}
}
}
});
//员工--先扫描再打印
Thread t2=new Thread(new Runnable(){
@Override
public void run(){
synchronized(s){
s.scan();
//休眠
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
synchronized(p){
p.print();
}
}
}
});
//开启线程
t1.start();
t2.start();
}
}
//定义代表扫描的类
class Scann{
public void scan(){
System.out.println("在呼哧呼哧的扫描。。。");
}
}
//第一代表打印的类
class Printer{
public void print(){
System.out.println("在哼哧哼哧的打印。。。");
}
}

6.消费生产模型

每次生产一个随机数量的商品,保证每次生产之后总的剩余商品数量不能超过1000。每次消费一个随机数据的商品,消费最大值是把总的剩余商品数量。生产和消费交替出现

等待唤醒机制(结合锁来使用)

通过wait()、notify()、notifyAll()以及标志位来控制线程对象执行顺序

public class WaitNotifyDemo{

public static void main(String[]args){
//商品类对象
Pruduct p=new Pruduct();

//创建线程对象---开启线程

new Thread(new Pruductor(p)).start();//生产者

new Thread(new Consumer(p)).start();//消费者
}
}
//定义类---代表线程执行任务信息(生产者)
class Pruductor implements Runnable{
//声明商品类的对象
private Pruduct p;
//有参构造---保证共享同一个商品类的对象
public Pruductor(Pruduct p){
this.p=p;
}
//生产过程
@Override
public void run(){
//保证一直生产下去
while(true){
synchronized(p){
if(p.getFlag()==true)
//让线程对象进行等待
try{
p.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
//可以生产的最大值
int max=1000-p.getCount();
//随机生产的商品数量
int count=(int)(Math.random()*(max+1));
//设置新的剩余的商品数量
p.setCount(p.getCount()+count);
//输出
System.out.println("生产了"+count+"个商品,还剩"+p.getCount()+"个商品。。。");
//唤醒等待线程对象
p.notify();
//改变布尔值
p.setFlag(true);
}
}
}
}
//定义类--代表线程执行任务信息(消费者)
class Consumer implements Runnable{
//声明商品类的对象
private Pruduct p;
//有参构造---保证共享同一个商品类的对象
public Consumer(Pruduct p){
this.p=p;
}
//指定消费过程
@Override
public void run(){
//保证一直消费下去
while(true){
synchronized(p){
if(p.getFlag()==false)
//线程对象等待
try{
p.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
//随机消费的商品数量
int count=(int)(Math.random()*(p.getCount()+1));
//设置新的剩余商品数量
p.setCount(p.getCount()-count);
//输出
System.out.println("消费了"+count+"个商品,还剩"+p.getCount()+"个商品。。。");
//唤醒等待的线程对象
p.notify();
//改变布尔值
p.setFlag(false);
}
}
}
}
//代表商品的类
class Pruduct{
//属性---商品数量
private int count;
//标志位
private boolean flag;
public boolean getFlag(){
return flag;
}
public void setFlag(boolean flag){
this.flag=flag;
}
public intget Count(){
return count;
}
public void setCount(int count){
this.count=count;
}
}
public class WaitNotifyAllDemo{
public static void main(String[]args){
//商品类对象
Pruductp=newPruduct();
//创建线程对象---开启线程
new Thread(new Pruductor1(p)).start();//生产者
new Thread(new Pruductor1(p)).start();//生产者
new Thread(new Pruductor1(p)).start();//生产者
new Thread(new Consumer1(p)).start();//消费者
new Thread(new Consumer1(p)).start();//消费者
new Thread(new Consumer1(p)).start();//消费者
}
}
//定义类---代表线程执行任务信息(生产者)
class Pruductor1 implements Runnable{
//声明商品类的对象
private Pruduct p;
//有参构造---保证共享同一个商品类的对象
public Pruductor1(Pruduct p){
this.p=p;
}
//生产过程
@Override
public void run(){
//保证一直生产下去
while(true){
synchronized(p){
//只判断一次
//if(p.getFlag()==true)
//会重新判断
while(p.getFlag()==true)
//让线程对象进行等待
try{
p.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
//可以生产的最大值
int max=1000-p.getCount();
//随机生产的商品数量
int count=(int)(Math.random()*(max+1));
//设置新的剩余的商品数量
p.setCount(p.getCount()+count);
//输出
System.out.println("生产了"+count+"个商品,还剩"+p.getCount()+"个商品。。。");
//唤醒等待线程对象
//p.notify();
//唤醒所有等待线程对象
p.notifyAll();
//改变布尔值
p.setFlag(true);
}
}
}
}
//定义类--代表线程执行任务信息(消费者)
class Consumer1 implements Runnable{
//声明商品类的对象
private Pruduct p;
//有参构造---保证共享同一个商品类的对象
public Consumer1(Pruduct p){
this.p=p;
}
//指定消费过程
@Override
public void run(){
//保证一直消费下去
while(true){
synchronized(p){
while(p.getFlag()==false)
//线程对象等待
try{
p.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
//随机消费的商品数量
int count=(int)(Math.random()*(p.getCount()+1));
//设置新的剩余商品数量
p.setCount(p.getCount()-count);
//输出
System.out.println("消费了"+count+"个商品,还剩"+p.getCount()+"个商品。。。");
//唤醒所有等待的线程对象
p.notifyAll();
//改变布尔值
p.setFlag(false);
}
}
}
}

7.wait()与sleep()方法的区别

sleep():使用时一定要给定休眠时间,到点自然醒。在休眠期间会释放线程对象的CPU的执行权(无论有锁还是没锁都会释放执行权但是如果有锁不会释放锁对象)。定义在Thread类里静态方法。

wait():使用时可以给定等待时间到点自然醒,但是如果没有指定等待时间需要强制进行唤醒。在等待期间释放线程对象的CPU执行权,释放锁对象。定义在Object类里。

重要 8.线程的状态
在这里插入图片描述

9.线程的优先级(一定程度上避免死锁的发生)

优先级从1到10,优先级级别逐渐增大。理论上优先级越大抢占到资源的概率就越大

理论上优先级之差大于5那么抢占到的资源的概率会稍微大一点

public class PriorityDemo{
public static void main(String[]args){
//创建线程对象
Thread t1=new Thread(new PDemo(),"A");
Thread t2=new Thread(new PDemo(),"B");
//设置优先级
t1.setPriority(1);
t2.setPriority(10);
//开启线程
t1.start();
t2.start();
}
}
//代表线程执行信息的类
class PDemo implements Runnable{
@Override
public void run(){
for(int i=0;i<=20;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
//休眠
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}

10.守护线程

当被守护线程执行结束所有的守护线程随之结束

当被守护线程出现多个时,所有的被守护线程结束,守护线程随之结束(类加载器—守护线程)

public class DaemonDemo{

public static void main(String[]args)throws InterruptedException{
//创建线程对象---四个小兵
Thread t1=new Thread(new Soldier(),"宫本");
Thread t2=new Thread(new Soldier(),"亚索");
Thread t3=new Thread(new Soldier(),"劫");
Thread t4=new Thread(new Soldier(),"提莫");
//设置守护线程
t1.setDaemon(true);
t2.setDaemon(true);
t3.setDaemon(true);
t4.setDaemon(true);
//开启线程
t1.start();
t2.start();
t3.start();
t4.start();
//BOSS---主线程---被守护线程
for(int i=20;i>=0;i--){
System.out.println("BOSS掉了一滴血,还剩"+i+"滴血...");
//休眠
Thread.sleep(5);
}
}
}
//代表小兵的类
class Soldier implements Runnable{
@Override
public void run(){
for(int  i=10;i>=0;i--){
System.out.println(Thread.currentThread().getName()
+"掉了一滴血,还剩"+i+"滴血...");
//休眠
try{
Thread.sleep(20);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值