暂停线程、多线程安全性及线程同步讲解

暂停线程执行

(1)final void join():调用该方法的线程强制执行,导致调用它的线程进入阻塞状态,而不会导致其它的线程阻塞。该线程执行完毕后,调用该线程的线程再继续执行。
(2)static void sleep(long millis):使当前正在执行的线程休眠millis毫秒,线程处于阻塞状态。
(3)static void yeild():当前正在执行的线程暂停一次,允许其他线程执行,不阻塞,只是回到就绪状态。如果没有其他等待执行的线程,则当前线程就会马上恢复执行。

线程的优先级

设置和获取当前线程优先级的方法
(1)final getPriority():获取线程的优先级
(2)filnal void setPriority(int priority):设置线程的优先级(并不是优先级越高就一定能先执行),优先级只能是1-10之间的整数

public class Test {
	public static void main(String[] args) {
		System.out.println("最高优先级:"+Thread.MAX_PRIORITY);
		System.out.println("最低优先级:"+Thread.MIN_PRIORITY);
		System.out.println("默认优先级:"+Thread.NORM_PRIORITY);
		//主线程的优先级
		Thread t=Thread.currentThread();
		System.out.println("获取主线程的优先级:"+t.getPriority());
		
		Thread t2=new Thread(new MyThread());
		System.out.println("新建的线程优先级为:"+t2.getPriority());
		/**
		 * 优先级超高越有可能先被调用执行,但是不一定
		 * 
		 */
		 t2.setPriority(6);
		 System.out.println("t2线程的优先级:"+t2.getPriority());
	 // t2.setPriority(100);  非法参数,因为优先级只能是1-10之间的整数
		 
	}
}
class MyThread implements Runnable{
	@Override
	public void run() {
	
	}
}
多线程安全性

假设一个这样的场景:一共还有5张车票,有三个窗口可以售最后这五张票,每个窗口有十人排队,5张票卖完了则结束。根据此场景用代码来表示如下:

public class TestTicket {
    public static void main(String[] args) {
        TicketThread th = new TicketThread();
        Thread t1 = new Thread(th,"窗口A");
        Thread t2 = new Thread(th,"窗口B");
        Thread t3 = new Thread(th,"窗口C");
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketThread implements Runnable{
    private  int ticket = 5;//5张车票
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            if(ticket>0){
                Thread t = Thread.currentThread();
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(t.getName()+"在售第"+(ticket--)+"票");
            }
        }
    }
}

出现的结果如下(由于多线程,cpu调度执行不唯一,所以运行结果不唯一)
在这里插入图片描述

我们发现出现了窗口A第0张票和窗口B销售第-1张票的错误。原因是当还有最后一张票时,即ticket=1时,线程t1进入判断条件(ticket>0),条件满足,然后让出资源,没有继续执行程序;此时线程t2得到资源,程序执行到判断条件(ticket>0),条件满足,然后让出资源,没有继续执行程序;此时线程t3得到资源,程序执行到判断条件(ticket>0),条件满足,然后打印语句和(ticket–),此时ticket=0;然后t1线程得到资源继续执行程序,所以此时窗口A打印出来的是第0张票,以此类推,线程t2(窗口B)打印出来的是第-1张票。这就是线程不安全,为了线程安全,我们应该控制当一个窗口售票工作结束时,其他窗口才能进行售票,这就需要用到线程同步。

线程同步

方法一:同步代码块,synchronized(obj){ },obj称为同步监听器

public class TestTicket1 {
    public static void main(String[] args) {
    TicketThread1 th = new TicketThread1();
    Thread t1 = new Thread(th,"窗口A");
    Thread t2 = new Thread(th,"窗口B");
    Thread t3 = new Thread(th,"窗口C");
    t1.start();
    t2.start();
    t3.start();
    }
}
class TicketThread1 implements Runnable{
    private int ticket = 5;
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            synchronized (this){
                if(ticket>0){
                    Thread t = Thread.currentThread();
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(t.getName()+"在售第"+(ticket--)+"票");
                }
            }

        }
    }
}

方法二:同步方法,public synchronized … 方法名(参数列表){ }

public class TestTicket2 {
    public static void main(String[] args) {
        TicketThread2 th = new TicketThread2();
        Thread t1 = new Thread(th,"窗口A");
        Thread t2 = new Thread(th,"窗口B");
        Thread t3 = new Thread(th,"窗口C");
        t1.start();
        t2.start();
        t3.start();
    }
}
class TicketThread2 implements Runnable{
    private int ticket = 5;
    @Override
    public void run() {
        //每个窗口排了10个人
        for (int i=0;i<10;i++) {
            //调用同步方法
            this.saleTicket();
        }
    }

    //同步方法,无需指定同步监视器,同步监视器只能是当前对象this

    public synchronized void saleTicket(){
        if(ticket>0){
            Thread t = Thread.currentThread();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(t.getName()+"在售第"+(ticket--)+"票");
        }
    }
}

用上了线程同步后,售票过程就正常了,线程同步原理是让一段代码连续执行完之后,其它线程才能有资格执行,即当执行同步代码时,其它线程进入阻塞。避免了线程间抢资源,导致出现不合理情况。

猜你喜欢

转载自blog.csdn.net/weixin_45684562/article/details/107738813