最近学习并发编程遇到不少问题,就顺手总结了有关多线程的几个常用的方法
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
长按识别二维码关注
微信扫一扫
关注该公众号
来源:CSDN
作者:jiangbr
链接:https://blog.csdn.net/jiangbr/article/details/79337573