Java 线程相关

 join  等待

        等待目标线程执行完毕,当前线程才会继续执行

class BThread extends Thread {
    public BThread() {
        super("[BThread] Thread");
    };
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(threadName + " loop at " + i);
                Thread.sleep(1000);
            }
            System.out.println(threadName + " end.");
        } catch (Exception e) {
            System.out.println("Exception from " + threadName + ".run");
        }
    }
}
class AThread extends Thread {
    BThread bt;
    public AThread(BThread bt) {
        super("[AThread] Thread");
        this.bt = bt;
    }
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        try {
            bt.join();
            System.out.println(threadName + " end.");
        } catch (Exception e) {
            System.out.println("Exception from " + threadName + ".run");
        }
    }
}
public class TestDemo {
    public static void main(String[] args) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        BThread bt = new BThread();
        AThread at = new AThread(bt);
        try {
            bt.start();
            Thread.sleep(2000);
            at.start();
            at.join();
        } catch (Exception e) {
            System.out.println("Exception from main");
        }
        System.out.println(threadName + " end!");
    }
}

main start.    //主线程起动,因为调用了at.join(),要等到at结束了,此线程才能向下执行。
[BThread] Thread start.
[BThread] Thread loop at 0
[BThread] Thread loop at 1
[AThread] Thread start.    //线程at启动,因为调用bt.join(),等到bt结束了才向下执行。
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end.
[AThread] Thread end.    // 线程AThread在bt.join();阻塞处起动,向下继续执行的结果
main end!      //线程AThread结束,此线程在at.join();阻塞处起动,向下继续执行的结果。

在AThread类中的run方法中,bt.join()是判断bt的active状态,如果bt的isActive()方法返回false,在 bt.join(),这一点就不用阻塞了,可以继续向下进行了。

sleep  暂停

        使当前线程暂停指定时间,CPU不忙的前提下 和指定时间相近,

具体暂停时间和CPU的性能有关

public class TestThreadSleep implements Runnable{
    public static void main(String[] args) {  
          
        TestThreadSleep runnable = new TestThreadSleep();  
        Thread thread = new Thread(runnable);  
        thread.start();  
    }  
    @Override  
    public void run() {  
          
        System.out.println("i am sleep for a while!");  
        try {  
            Date currentTime = new Date();  
            long startTime = currentTime.getTime();  
            Thread.sleep(4000);  
            currentTime = new Date();  
            long endTime = currentTime.getTime();  
            System.out.println("休眠时间为:"+(endTime-startTime)+"ms");  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
}

.currentThread()获取当前线程

多线程的情况下...

public class Demo {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt).start();
        new Thread(mt, "Name1").start();
        new Thread(mt, "Name2").start();

        System.out.println(Thread.currentThread().getName()); // main主方法
        //      System.out.println(this.getName());                   // this获取不到线程对象
    }
}

class MyThread extends Thread {@Override public void run() {
        try {
            Thread.sleep(3000);
            Thread t = Thread.currentThread();
            System.out.println("当前线程名字:" + t.getName() + " 当前线程的优先级别为:" + t.getPriority() + " ID:" + t.getId());
            //           System.out.println("当前线程名字:" + this.getName() + " 当前线程的优先级别为:" + this.getPriority() + " ID:"+ this.getId());
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Thread.interrupt()

1. Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,设置线程的中断标示位,在线程受到阻塞的地方(如调用sleep、wait、join等地方)抛出一个异常InterruptedException,并且中断状态也将被清除,这样线程就得以退出阻塞的状态。
2. 一般来说,阻塞函数,如:Thread.sleep、Thread.join、Object.wait等在检查到线程的中断状态时,会抛出InterruptedException,同时会清除线程的中断状态

class Example3 extends Thread {
    public static void main(String args[]) throws Exception {
        Example3 thread = new Example3();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        thread.interrupt();// 等中断信号量设置后再调用
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }

    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println("Thread running...");
            try {
                /*
                 * 如果线程阻塞,将不会去检查中断信号量stop变量,所 以thread.interrupt()
                 * 会使阻塞线程从阻塞的地方抛出异常,让阻塞线程从阻塞状态逃离出来,并
                 * 进行异常块进行 相应的处理
                 */
                Thread.sleep(1000);// 线程阻塞,如果线程收到中断操作信号将抛出异常
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted...");
                /*
                 * 如果线程在调用 Object.wait()方法,或者该类的 join() 、sleep()方法
                 * 过程中受阻,则其中断状态将被清除
                 */
                System.out.println(this.isInterrupted());// false

                //中不中断由自己决定,如果需要真真中断线程,则需要重新设置中断位,如果
                //不需要,则不用调用
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Thread exiting under request...");
    }
}

synchronized同步锁

        在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如synchronized(obj)就获取了“obj这个对象”的同步锁。

多线程的实现 

方法一:

实现  Runnable 接口 新建实例对象时  Thread thread1 = new Thread(demo1);  

用 Thread 类包裹该实例

public class ThreadDemo1 implements Runnable {
    private int countDown = 10;
    @Override
    //重写run方法,定义任务
    public void run() {
        while(countDown-- >0)
        {
            System.out.println("$" + Thread.currentThread().getName() 
                    + "(" + countDown + ")");
        }
    }
    //调用start方法会启动一个线程,导致任务中的run方法被调用,run方法执行完毕则线程终止
    
    public static void main(String[] args) {
        Runnable demo1 = new ThreadDemo1();
        
        Thread thread1 = new Thread(demo1);
        Thread thread2 = new Thread(demo1);
        thread1.start();
        thread2.start();
        
        System.out.println("火箭发射倒计时:");
    }
}

继承 Thread

方法二:

        thread 实现了 runnable 接口,实现Runable接口才是真正的多线程,

所以 用第一种方法更合适

public class ExtendFromThread extends Thread {
    private int countDown = 10;
    @Override
    //重写run方法,定义任务
    public void run() {
        while(countDown-- >0)
        {
            System.out.println("$" + this.getName() 
                    + "(" + countDown + ")");
        }
    }
    //调用start方法会启动一个线程,导致任务中的run方法被调用,run方法执行完毕则线程终止
    
    public static void main(String[] args) {
        
        ExtendFromThread thread1 = new ExtendFromThread();
        ExtendFromThread thread2 = new ExtendFromThread();
        thread1.start();
        thread2.start();
        
        System.out.println("火箭发射倒计时:");
    }
}

优缺点

采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

 yield()

将 运行中 变为 可运行 

 同步锁

等待被唤醒和唤醒操作必须在同步锁内完成

  synchronized(obj) {

            obj.wait();  //等待其他线程将本线程唤醒
            obj.notifyAll();  //唤醒所有线程
       }

public class NotifyAllTest {
    private static Object obj = new Object();
    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");
        ThreadA t2 = new ThreadA("t2");
        ThreadA t3 = new ThreadA("t3");
        t1.start();
        t2.start();
        t3.start();

        try {
            System.out.println(Thread.currentThread().getName()+" sleep(3000)");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(obj) {
            // 主线程等待唤醒。
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
    }

    static class ThreadA extends Thread{

        public ThreadA(String name){
            super(name);
        }

        public void run() {
            synchronized (obj) {
                try {
                    // 打印输出结果
                    System.out.println(Thread.currentThread().getName() + " wait");

                    // 唤醒当前的wait线程
                    obj.wait();

                    // 打印输出结果
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/*
    t1 wait
    main sleep(3000)
    t3 wait
    t2 wait
    main notifyAll()
    t2 continue
    t3 continue
    t1 continue
*/

调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A,当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。

Runnable接口和Callable接口的区别

有点深的问题了,也看出一个Java程序员学习知识的广度。

Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

volatile

多线程主要围绕可见性和原子性两个特性而展开,使用volatile关键字修饰的变量,保证了其在多线程之间的可见性,即每次读取到volatile变量,一定是最新的数据

demo 

public class ThreadTest implements Runnable {
    public static int shareVar = 0;
    public synchronized void run() {
        if (shareVar == 0) {
            for (int i = 0; i < 10; i++) {
                shareVar++;
                if (shareVar == 5) {
                    try {
                        this.wait();
                    } catch(Exception e) {}
                }
            }
        }
        if (shareVar != 0) {
            System.out.print(Thread.currentThread().getName());
            System.out.println(" shareVar = " + shareVar);
            this.notify();
        }
    }

    public static void main(String[] args) {
        Runnable r = new ThreadTest();
        Thread t1 = new Thread(r, "t1");
        10 Thread t2 = new Thread(r, "t2");
        t1.start();
        t2.start();
    }
}

运行结果 : 

t2 shareVar = 5
t1 shareVar = 10

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值