java_关于线程常用操作及同步锁

线程API:

常用构造器:

    Thread(Runnable r)
        创建一个指定任务的线程对象
    Thread(Runnable r, String name)
        创建一个指定任务,指定名称的线程对象
    Thread(String name)
        创建一个指定名称的线程对象

常用方法:

    String getName();获取线程名称
    long getId();获取线程ID
    int getPriority();获取优先级
    boolean isAlive();线程是否活动状态
    boolean isDaemon();线程是否为守护(后台)线程
    Thread.State getState();获取线程状态
    boolean isInterrupted():是否被打断
    void interrupt():打断阻塞状态下的线程对象
    static void yield():线程对象让步的功能(让出时间片段,回到就绪状态)

线程调度:

即优先级
1-10,10为最高,1最低,5默认
Thread.MIN_PRIORITY–最小优先级
Thread.MAX_PRIORITY–最高优先级
Thread.NORM_PRIORITY–默认优先级
对应的方法:
void setPriority(int priority)
用于设置线程调度(优先级)

守护线程:

线程分两类
一类是普通线程(前台线程),一类是守护线程(后台线程)
当线程只剩下守护线程时,所有线程都结束(死亡)。

void setDaemon(boolean on)
true将此线程标记为守护线程,false将此线程标记为普通线程(不调用方法,默认为false)

/**
 * 守护线程的学习:
 * 
 * 模拟rose和jack两个人跳水
 * rose:喊10次跳水,然后噗通一声,结束
 * jack:你跳我就跳,rose跳水后,结束 
 */
public class DeamonDemo {
    public static void main(String[] args) {
        Thread rose = new Thread(){
            public void run(){
                for(int i=0;i<10;i++){
                    try {
                        Thread.sleep(500);
                        System.out.println("我要跳了");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("------噗通------");
            }
        };
        Thread jack = new Thread(){
            public void run(){
                while(true){
                    try {
                        Thread.sleep(500);
                        System.out.println("你跳我就跳");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        /*将jack设置成守护线程,注:需要在启动之前设置才有效*/
        jack.setDaemon(true);
        rose.setPriority(Thread.MAX_PRIORITY);
        jack.setPriority(Thread.MIN_PRIORITY);
        rose.start();
        jack.start();
    }
}

测试结果:
这里写图片描述

其他堵塞的两个方法

static sleep(long time)
用于使当前线程进入阻塞状态,时间为time毫秒,time毫秒后,会进入就绪状态,若期间被打断,会出现异常InterruptedException
void join()
将当前线程(调用方法的线程对象)插入到某一个线程中,使某一个线程进入阻塞状态,当前线程执行完(死亡)后,另一个线程进入就绪状态

同步锁:

/**
 * 模拟2个人捡豆子
 * 桌上有20可豆子
 * 每人1秒拿走一颗豆子
 */
public class Bean implements Runnable{
    static int num = 20;
    public void run(){
        while(num>0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("剩余豆子"+ --num);
        }
    }
    public static void main(String[] args) {
        Runnable r = new Bean();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}

这里写图片描述
这里写图片描述
当多个线程操作临界资源时,可能会出现线程安全隐患问题
临界资源可能是:
(1)静态资源
(2)实例变量
想解决该问题,需要使用同步操作

异步操作
多线程的并发操作,相当于各干各的
同步操作
相当于一个做完,另一个再做

线程在内部提供了一个内置的锁机制保证原子性,用于线程进行同步操作

锁:需要注意两点
(1)锁是一个对象
(2)若想同步操作,多个线程操作的必须是同一个锁对象

synchronized(锁对象的引用){
    需要同步的代码块
}
锁机制
当一个线程执行到同步代码块后,会得到锁对象的使用权,其他线程若执行到此处,会发现锁对象被占用,处于等待,线程执行完同步代码块后,或者出现异常,都会自动释放锁对象。
合适的锁对象
必须是一个引用类型,而且必须使多个线程都可以使用这个锁对象,因此this对象比较适合

同步块的范围

(1)可以是方法内的一部分方法,可以是全部代码(相当于给方法上了锁)

/**
 * 模拟2个人捡豆子
 * 桌上有20可豆子
 * 每人1秒拿走一颗豆子
 */
public class Bean implements Runnable{
    static int num = 20;
    public void run(){
        while(num>0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(this){
                if(num>0){
                    System.out.println("剩余豆子"+ --num);
                }
            }
        }
    }
    public static void main(String[] args) {
        Runnable r = new Bean();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}

多运行几次,结果都是相同的
这里写图片描述

(2)给成员方法上添加修饰词synchronized,锁对象为this
如果一个类的所有成员方法都是用了synchronized时,当某个线程操作了一个方法,另外的线程即使操作的不是这个方法,也会进入锁池状态

/**
 * 模拟计算器运算
 * 分别计算加法减法结果
 */
public class Computer{
    private int a;
    private int b;
    public Computer(int a, int b) {
        this.a = a;
        this.b = b;
    }
    /**加法运算*/
    public synchronized void add(){
        System.out.println("开始计算加法");
        int sum = a+b;
        System.out.println("得出加法结束");
        System.out.println("加法结果为"+sum);
    }
    /**减法运算*/
    public synchronized void sub(){
        System.out.println("开始计算减法");
        int sub = a-b;
        System.out.println("得出减法结果");
        System.out.println("减法结果为"+sub);
    }
    public static void main(String[] args) {
        Computer c = new Computer(4,2);
        Thread t1 = new My1(c);
        Thread t2 = new My2(c);
        t1.start();
        t2.start();
    }
}
/**线程1:计算加法*/
class My1 extends Thread{
    private Computer com;

    public My1(Computer com) {
        this.com = com;
    }
    public void run(){
        com.add();
    }
}
/**线程2:计算减法*/
class My2 extends Thread{
    private Computer com;

    public My2(Computer com) {
        this.com = com;
    }
    public void run(){
        com.sub();
    }
}

这里写图片描述

(3)静态方法上也可以添加synchronized,锁对象为类对象,调用方式:类名.class,每个类都有一个唯一的类对象

等待阻塞

注:只能在同步锁中使用

wait():
当前获取锁对象的线程准备释放锁,给其他线程获取锁的机会
wait(long time):
当前获取锁对象的线程(没有被通知)在延迟time毫秒后自动释放锁对象
wait(long time,int naons):
比上一个方法延迟时间更加精确(在毫秒(10^-3s)后,添加一个纳秒(10^-9s))
notify()/notifyAll():
当前获取锁对象的线程准备释放锁,使用此方法通知处于wait方法等待的线程,让等待的线程开始准备竞争锁对象,当前调用的线程仍在运行状态
notify():只会随机通知等待线程中的其中一个
notifyAll():通知所有等待线程

猜你喜欢

转载自blog.csdn.net/yc_hen/article/details/82312596