DAY 21

day21

线程的优先级

1.MAX_PRIORITY:10

NORM_PRIORITY:5

MIN_PRIORITY:1

2.获取和设置当前线程的优先级

getPriority:获取线程的优先级

setPriority(int p):设置线程的优先级

说明:高优先级的线程要抢占低优先级线程cpu的执行权。但只是从概率上来讲,高优先级的线程高概率的情况下被执行,并不意味着只有当高优先级的线程被执行完以后,低优先级的线程才被执行

方式二:实现Runnable接口

1.创建一个实现了Runnable接口的类

2.实现类去实现Runnable中的抽象方法:run()

3.创建实现类的对象

4.将此对象作为参数传递到Thread类的对象调用start()

package shangGuiGu.day21;
//创建三个窗口卖票,总票数为100票
class window extends Thread{
    private static int ticket=100;
    public void run(){
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+":卖票,票号为"+ticket);
                ticket--;
            }else{
                break;
            }
        }
    }
}
public class demo02 {
    public static void main(String[] args) {
        window w1=new window();
        window w2=new window();
        window w3=new window();
        w1.setName("窗口1");
        w1.setName("窗口2");
        w1.setName("窗口3");
        w1.start();
        w2.start();
        w3.start();
    }
}
package shangGuiGu.day21;

class mthread implements Runnable{
    public void run(){
        for(int i=0;i<100;i++){
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
public class demo03 {
    public static void main(String[] args) {
        mthread mthread=new mthread();
        Thread t1 = new Thread(mthread);
        t1.start();
        t1.setName("线程1");
        Thread t2 = new Thread(mthread);
        t2.start();
        t2.setName("线程二");
    }
}

package shangGuiGu.day21;
//创建三个窗口卖票,总票数为100票,使用实现Runnable接口的方式
class window1 implements Runnable{
    private int ticket=100;
    public void run(){
        while(true){
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
                ticket--;
            }else{
                break;
            }
        }
    }
}
public class demo01 {
    public static void main(String[] args) {
        window1 w=new window1();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t1.setName("窗口2");
        t1.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
比较创建线程的两种方式

开发中,优先选择实现Runnable接口的方式

原因:1.实现的方式没有类的单继承性的局限性

2.实现的方式更适合来处理多个线程有共享数据的情况

联系:public class Thread implements Runnable

相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中

线程的安全问题

1.问题:买票过程中,出现了重票、错票

2.出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票

3.解决问题:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。

4.在java中通过同步机制来解决线程安全问题

方式一:同步代码块

synchronize(同步监视器)

{//需要被同步的代码

}

说明:1.操作共享数据的代码即为需要被同步的代码

2.共享数据:多个线程共同操作的变量。例如:ticket

3.同步监视器,俗称:锁。任何一个类的对象都可以充当锁。要求:多个线程必须要共用同一把锁

补充:在实现Runnable接口创建多线程的方式中,可以考虑使用this充当同步监视器

方式二:同步方法

若操作共享数据的代码完整的声明在一个方法中,不妨将此方法声明同步的

package shangGuiGu.day21;

class window2 implements Runnable{
    private int ticket=100;
    Object obj=new Object();
    public  void run(){
       show();
    }
    private synchronized void show(){//同步监视器:this
        while(true){
            synchronized(obj){
                if(ticket>0){
                    System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
                    ticket--;
                }

            }}
    }
}
public class demo04 {
    public static void main(String[] args) {
        window1 w=new window1();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t1.setName("窗口2");
        t1.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

关于同步方法的总结:

1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明

2.非静态的同步方法,同步监视器是this

静态的同步方法,同步监视器是当前类本身

死锁问题

1.理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

2.说明:①出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

②使用同步时,要避免出现死锁

方法三:Lock锁

package shangGuiGu.day21;

import java.util.concurrent.locks.ReentrantLock;

class windoww implements Runnable{
    private int ticket=100;
    //1.实例化ReentrantLock
    private ReentrantLock lock1=new ReentrantLock(true);
    Object obj=new Object();
    public void run(){
        while(true){
            try{
                //调用锁定lock方法
                lock1.lock();
                if(ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
                    ticket--;
                }else{
                    break;
                }
            }finally {
                //调用解锁方法:unlock
                lock1.unlock();
            }
        }
    }
}
public class demo07 {
    public static void main(String[] args) {
        window1 w=new window1();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t1.setName("窗口2");
        t1.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

synchronized与lock方法的不同:

synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器

lock需要手动的启动同步(lock),同时结束同步也需要手动的实现(unlock)

package shangGuiGu.day21;
class account{
    private double balance;

    public account(double balance) {
        this.balance = balance;
    }
    //存钱
    public synchronized void deposit(double amt){
        if(amt>0){
            balance+=amt;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"存钱成功,余额为:"+balance);
        }
    }
}
class customer extends Thread{
    private account a1;

    public customer(account acct) {
        this.a1=acct;
    }
    public void run(){
        for(int i=0;i<3;i++){
            a1.deposit(1000);
        }
    }
}
public class demo08 {
    public static void main(String[] args) {
        account acct=new account(0);
        customer c1 = new customer(acct);
        customer c2 = new customer(acct);
        c1.setName("甲");
        c2.setName("乙");
        c1.start();
        c2.start();
    }
}
线程的通信

涉及到的三个方法:

wait:一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器

notify:一旦执行此方法,就会唤醒被wait的一个线程。若有多个线程被wait,就唤醒优先级高的线程

notifyall:一旦执行此方法,就会唤醒所有被wait的线程

说明:

1.三种方法必须使用在同步代码块或同步方法中。

2.三个方法的调用者必须是同步代码块或同步方法中的同步监视器,否则会出现illegalmonitorstateexception异常

3.三个方法是定义在object类中

package shangGuiGu.day21;
class number implements Runnable{
    private  int number1=1;
    public void run(){
        while(true){
            synchronized (this){
                notify();
            if(number1<=100){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":"+number1);
           number1++;

                try {
                    //使得调用如下wait方法的线程进入阻塞状态
                    wait();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                break;
            }}
        }
    }
}
public class demo09 {
    public static void main(String[] args) {
        number number2 = new number();
        Thread t1=new Thread(number2);
        Thread t2=new Thread(number2);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值