第10章-第4节-Java中多线程Thread里面的常用方法

Thread的常用方法:

1、Thread类:

public class Thread implements Runnable {
    // 线程名字
    private volatile String name;
    // 线程优先级(1~10)
    private int priority;  //yeild  当前线程礼让,如果有高优先级,高优先级的先跑
    // 守护线程
    private boolean daemon ;
    // 线程id
    private long tid;
    // 线程组
    private ThreadGroup group;
    
    // 预定义3个优先级
    public final static int MIN_PRIORITY = 1;
    public final static int NORM_PRIORITY = 5;
    public final static int MAX_PRIORITY = 10;
    
    
    // 构造函数
    public Thread();
    public Thread(String name);
    public Thread(Runnable target);
    public Thread(Runnable target, String name);
    // 线程组
    public Thread(ThreadGroup group, Runnable target);
    
    
    // 返回当前正在执行线程对象的引用
    public static native Thread currentThread();
    
    // 启动一个新线程
    public synchronized void start();
    // 线程的方法体,和启动线程没关系
    public void run();
    
    // 让线程睡眠一会,由活跃状态改为挂起状态
    public static native void sleep(long millis) throws InterruptedException;
    public static void sleep(long millis, int nanos) throws InterruptedException;
    
    // 打断线程 中断线程 用于停止线程
    // 调用该方法时并不需要获取Thread实例的锁。无论何时,任何线程都可以调用其它线程的interruptf方法
    public void interrupt();
    public boolean isInterrupted()
    
    // 线程是否处于活动状态
    public final native boolean isAlive();
    
    // 交出CPU的使用权,从运行状态改为挂起状态
    public static native void yield();
    
    public final void join() throws InterruptedException
    public final synchronized void join(long millis)
    public final synchronized void join(long millis, int nanos) throws InterruptedException
    
    
    // 设置线程优先级
    public final void setPriority(int newPriority);
    // 设置是否守护线程
    public final void setDaemon(boolean on);
    // 线程id
    public long getId() { return this.tid; }
    
    
    // 线程状态
    public enum State {
        // new 创建
        NEW,

        // runnable 就绪
        RUNNABLE,

        // blocked 阻塞
        BLOCKED,

        // waiting 等待
        WAITING,

        // timed_waiting
        TIMED_WAITING,

        // terminated 结束
        TERMINATED;
    }
}
public static void main(String[] args) {
    // main方法就是一个主线程

    // 获取当前正在运行的线程
    Thread thread = Thread.currentThread();
    // 线程名字
    String name = thread.getName();
    // 线程id
    long id = thread.getId();
    // 线程优先级
    int priority = thread.getPriority();
    // 是否存活
    boolean alive = thread.isAlive();
    // 是否守护线程
    boolean daemon = thread.isDaemon();

    // Thread[name=main, id=1 ,priority=5 ,alive=true ,daemon=false]
    System.out.println("Thread[name=" + name + ", id=" + id + " ,priority=" + priority + " ,alive=" + alive + " ,daemon=" + daemon + "]");
}

2、start()和run():

public static void main(String[] args) throws Exception {
   new Thread(()-> {
       for (int i = 0; i < 5; i++) {
           System.out.println(Thread.currentThread().getName() + " " + i);
           try { Thread.sleep(200); } catch (InterruptedException e) { }
       }
   }, "Thread-A").start();

   new Thread(()-> {
       for (int j = 0; j < 5; j++) {
           System.out.println(Thread.currentThread().getName() + " " + j);
           try { Thread.sleep(200); } catch (InterruptedException e) { }
       }
   }, "Thread-B").start();
}

start(): 启动一个线程,线程之间是没有顺序的,是按CPU分配的时间片来回切换的。

public static void main(String[] args) throws Exception {
    new Thread(()-> {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            try { Thread.sleep(200); } catch (InterruptedException e) { }
        }
    }, "Thread-A").run();
new Thread(()-> {
    for (int j = 0; j < 5; j++) {
        System.out.println(Thread.currentThread().getName() + " " + j);
        try { Thread.sleep(200); } catch (InterruptedException e) { }
    	}
    }, "Thread-B").run();
}

 run(): 这个方法不能手动调用,用了start()后自动调用。调用线程的run方法,就是普通的方法调用,虽然将代码封装到两个线程体中,可以看到线程中打印的线程名字都是main主线程,run()方法用于封装线程的代码,具体要启动一个线程来运行线程体中的代码(run()方法)还是通过start()方法来实现,调用run()方法就是一种顺序编程不是并发编程。

3、wait()和notify():

  • wait、notify和notifyAll方法是Object类的final native方法。所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序中可以通过this或者super来调用this.wait(), super.wait()

  • wait(): 导致线程进入等待阻塞状态,会一直等待直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。wait(long timeout): 时间到了自动执行,类似于sleep(long millis)

  • notify(): 该方法只能在同步方法或同步块内部调用, 随机选择一个(注意:只会通知一个)在该对象上调用wait方法的线程,解除其阻塞状态

  • notifyAll(): 唤醒所有的wait对象

注意:

Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部 让哪个对象等待wait就去通知notify哪个对象,不要让A对象等待,结果却去通知B对象,要操作同一个对象

Object

public class Object {
	public final void wait() throws InterruptedException;
	public final native void wait(long timeout) throws InterruptedException;
	public final void wait(long timeout, int nanos) throws InterruptedException;
	
	
	public final native void notify();
	public final native void notifyAll();
}

 WaitNotifyTest

public class WaitNotifyTest {
    public static void main(String[] args) throws Exception {
        WaitNotifyTest waitNotifyTest = new WaitNotifyTest();
        new Thread(() -> {
            try {
                waitNotifyTest.printFile();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            try {
                waitNotifyTest.printFile();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            try {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t睡觉1秒中,目的是让上面的线程先执行,即先执行wait()");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            waitNotifyTest.notifyPrint();
        }).start();
    }

    private synchronized void printFile() throws InterruptedException {
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t等待打印文件...");
        this.wait();
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t打印结束。。。");
    }

    private synchronized void notifyPrint() {
        this.notify();
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t通知完成...");
    }
}

4、sleep()和wait():

Thread.sleep(long millis): 睡眠时不会释放锁

public static void main(String[] args) throws InterruptedException {
    Object lock = new Object();
    new Thread(() -> {
        synchronized (lock) {
            for (int i = 0; i < 5; i++) {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
                try { Thread.sleep(1000); } catch (InterruptedException e) { }
            }
        }
    }).start();

    Thread.sleep(1000);

    new Thread(() -> {
        synchronized (lock) {
            for (int i = 0; i < 5; i++) {
                System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
            }
        }
    }).start();
}

 因main方法中Thread.sleep(1000)所以上面的线程Thread-0先被执行,当循环第一次时就会Thread.sleep(1000)睡眠,因为sleep并不会释放锁,所以Thread-1得不到执行的机会,所以直到Thread-0执行完毕释放锁对象lock,Thread-1才能拿到锁,然后执行Thread-1;

5、总结:

1)、sleep方法和wait方法的区别:
         1>、 sleep方法是Thread类的,wait方法是 Object类的
         2>、sleep方法 需要传入时间毫秒数 参数, wait 可传 也可以 不传参数
                wait方法传入参数,那么和sleep方法类似,在等待指定时间后,会自动恢复为 就绪状态
                wait方法如果不传参数,会一直处于等待状态=阻塞状态  , 这种只能手动唤醒
         3>、sleep方法释放cpu资源但是不释放锁资源,可以在无锁的环境中使用
       wait方法 释放cpu + 锁资源 ,  必须在有锁的 环境中使用!

2)、start 方法 和 run 方法
         start 方法代表线程进入到 就绪状态 = 该线程拥有抢占cpu资源的 资格
         run 方法 代表 线程进入到 运行状态

         start方法可以手动调用,当线程抢到资源后,会自动执行run方法
         run方法不能手动强行执行,执行不会报错,但是不代表线程开始!

3)、join方法  插队方法
         调用该方法后,该线程会优先执行,可以传入时间参数=给与该线程的执行时间
4)、yield 方法  礼让方法
         调用该方法,该线程会退出执行状态,重新抢占时间片资源  , 一般使用在 给高优先级线程资源的时候 使用!!!

5)、守护线程   isDaemon() 查看该线程是否是守护线程
         setDaemon() 设置该线程是否为守护线程,默认 自定义线程为  非守护线程,守护线程 : 该线程会跟随主线程一起运行完毕,哪怕 该线程自己还没有执行完毕

本电子书目录:《Java基础的重点知识点全集》 

你可能感兴趣的:(java)