多线程常用的几个方法汇总


最近学习并发编程遇到不少问题,就顺手总结了有关多线程的几个常用的方法

sleep()

sleep()方法属于Thread类,主要的作用是让当前线程停止执行,把cpu让给其他线程执行,但不会释放对象锁和监控的状态,到了指定时间后线程又会自动恢复运行状态

注意:线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行

  • 另外

    • Thread.sleep()方法是一个静态方法

    • Java有两种sleep方法,一个只有一个毫秒参数,另一个有毫秒和纳秒
      个参数第三代

sleep(long millis)

or

sleep(long millis, int nanos)

1//此try语句块放在run方法内
2try {
3            Thread.sleep(1000);
4       } catch (InterruptedException e) {
5            // TODO 自动生成的 catch 块
6            e.printStackTrace();
7       }

wait() notify()

wait()属于Object类,与sleep()的区别是当前线程会释放锁,进入等待此对象的等待锁定池。比方说,线程A调用Obj.wait(),线程A就会停止运行,而转为等待状态。至于等待多长时间? 那就看其他线程是否调用Obj.notify().其优势显而易见,成为多个线程之间进行通讯的有手段!

注意:它必须包含在Synchronzied语句中,无论是wait()还是notify()都需要首先获得目标的对象的一个监视器

  • 先来解释一下 "Synchronzied" 
    是一种同步锁。作用是实现线程间同步,对同步的代码加锁,使得每一次,只能有一线程进入同步块,从而保证线程间的安全性

它修饰的对象有以下几种:

  • 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的部分,进入同步代码前要获得给定对象的锁

  • 修饰一个实例方法,进入同步代码前要获得当前实例的锁

  • 修饰一个静态方法,进入同步代码前要获得当前类的锁

先给大家一个例子:

 1public class SimpleWN {
2    public static int count=0;
3    public static class one implements Runnable{
4        @Override
5        public void run() {
6            for (int i = 0; i < 100; i++) {
7                synchronized (this) {
8                    count++;
9                }
10            }                          
11        }  
12    }
13    public static void main(String[] args) throws InterruptedException {
14        Thread t1=new Thread(new one());
15        Thread t2=new Thread(new one());
16        t1.start();
17        t2.start();
18        t1.join();
19        t2.join();
20        System.out.println(count);
21    }
22}

不知道大家看出这段代码有一个严重错误。代码17,18行,两个线程实例的不是同一个对象,这也意味两个线程使用的是两把不同的锁,没法保证同步。多运行几次就会发现有时候结果并不是200

更正做法:

1    one oo=new one();
2    Thread t1=new Thread(oo);
3    Thread t2=new Thread(oo);

举例说明程序中应用wait() 和 notify():

 1public class SimpleWN {
2    final static Object object=new Object();
3    public static class one extends Thread{
4        @Override
5        public void run() {
6            synchronized (object) {
7                System.out.println("T1 开始");
8                try {
9                    System.out.println("T1 等待");
10                    object.wait();
11                } catch (InterruptedException e) {
12                    e.printStackTrace();
13                }
14                System.out.println("T1 结束");
15            }                  
16        }  
17    }
18    public static class two extends Thread{
19        @Override
20        public void run() {
21            synchronized (object) {
22                System.out.println("T2 开始");
23                System.out.println("释放一个线程");
24                object.notify();
25                System.out.println("T2 结束");
26            }                  
27        }  
28    }
29    public static void main(String[] args) throws InterruptedException {
30        Thread t1=new one();
31        Thread t2=new two();
32        t1.start();
33        t2.start();
34        t1.join();
35        t2.join();
36    }
37}

运行结果:

1T1 开始
2T1 等待
3T2 开始
4释放一个线程
5T2 结束
6T1 结束

join()

在某些情况下,子线程需要进行大量的耗时运算,主线程可能会在子线程执行结束之前结束,但是如果主线程又需要用到子线程的结果,换句话说,就是主线程需要在子线程执行之后再结束。这就需要用到join()方法

 1public class BigJoin {
2    public static int count;
3    public static class AddThread implements Runnable{
4        @Override
5        public void run() {
6            for (int i = 0; i < 1000000000; i++) {
7                count++;
8            }  
9        }  
10    }
11    public static void main(String[] args) throws InterruptedException {
12        // TODO 自动生成的方法存根
13        AddThread addThread=new AddThread();
14        Thread t1=new Thread(addThread);
15        t1.start();
16        t1.join();
17        System.out.println(count);
18    }
19}

yield()

中文意思:放弃,屈服
一个线程调用yield()意味着告诉虚拟机自己非常乐于助人,可以把自己的位置让给其他线程(这只是暗示,并不表绝对)。但得注意,让出cpu并不代表当前线程不执行了。当前线程让出cpu后,还会进行cpu资源的争夺,但是能不能再次分配到,就不一定了

 1public class SimpleYield extends Thread{
2    String name=null;
3    public  SimpleYield(String name) {
4        super(name);
5    }
6    @Override
7    public void run() {
8        // TODO 自动生成的方法存根
9        for(int i=1;i<=10;i++){
10            System.out.println(this.getName()+i);
11            if(i==5){
12                this.yield();
13            }
14        }
15    }
16    public static void main(String[] args) throws InterruptedException {
17        SimpleYield t1=new SimpleYield("小花");
18        SimpleYield t2=new SimpleYield("小草");
19        t1.start();
20        t2.start();
21    }
22}

运行结果:这只是其中一种结果,线程(小花)的执行到2时把cpu让给线程(小草)并执行,接下来-线程(小草)的执行到2时把cpu让给线程(小花)并执行

1小花1
2小花2
3小草1
4小草2
5小花3
6小花4
7小草3
8小草4

长按识别二维码关注


微信扫一扫
关注该公众号

展开阅读全文
  • 7
    点赞
  • 2
    评论
  • 24
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值