Java巩固之路-----多线程(二)线程的基本操作及原理

在java中,线程在运行的时候,经常会用到各种方法,控制线程的状态。以下,就是对这些方法的操作demo及原理分析

Thread.join()

首先,我们要了解,join方法的注释

Waits for this thread to die.

一直等到这个线程死亡。

谁调用,谁就可以优先执行完。

因此Thread.join()方法可以保证线程执行结果的可见性。

下面举例说明

public class JoinDemo extends Thread {

   private static int i = 0;


   public static void main(String[] args) throws InterruptedException {

      Thread t1 = new Thread(()->{

         i=1;
      });
      
      Thread t2 = new Thread(()->{
         i = 2;
      });

      t1.start();
//    t1.join();
      t2.start();
      Thread.sleep(100);
      System.out.println("result: "+i);
   }
}

在这样一个简单的代码中。main方法中创建两个线程,一个初始化i=1,一个初始化i=2;

这个main方法运行的时候,打印出来i的值不确定,t1先执行完,i=2;t2先执行完 i=1

但是当我们将t1.join()注释放开后,执行结果就肯定是i=2;

在这个main方法运行的时候,一共会创建三个线程。

main主线程,t1线程,t2线程。主线程调用了t1.join()方法。那他到这句的时候就会wait。一直会wait到t1die。

只有等t1执行完了。主线程才会继续执行,创建t2.

主要流程如下。

所以,当任意一个线程调用了其他线程的Thread.join()方法,就要等待这个线程执行完毕。

如果是Thread.join(long) ,就是等待线程执行完毕或者时间到。才会继续执行。

所以这个join方法就类似与我们生活中的排队买票:

我一直在排队买票,

少一个人我往前进一步,

忽然我看到女神也过来买票,我说:女神,你join到我前面。那我就要一直等待女神买完票。

这个join方法就是给自己添堵,让自己阻塞。处于wait状态

Thread.sleep()

工作流程:

1、挂起线程并修改运行状态

2、用sleep方法中传入的毫秒数设置一个定时器

3、时间结束,定时器触发,线程会被修改到就绪状态重新等待时间片分配

public class SleepDemo extends Thread {

   @Override
   public void run() {
      
      try {
         System.out.println("begin:" + System.currentTimeMillis());
         Thread.sleep(1000);
         System.out.println("end  :" + System.currentTimeMillis());
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      SleepDemo sleepDemo = new SleepDemo();
      sleepDemo.start();
   }
}

以上是一个简单的线程,触发sleep方法。

但是通过end-begin。发现相差时间超过1000毫秒。多出来的时间就是抢占时间片的时间,这个时间的大小应该跟CPU和当前就绪状态线程数有关。

sleep(0)的作用

根据sleep(long)的流程,我们可以推断,long为0时,线程的状态挂起后瞬间变为就绪。

所有sleep(0)的功能类似于Thread.yield()

notify和wait

wait()

wait方法很明显。就是让一个线程由运行状态,进入到WAITING状态。

wait(long)

让一个线程由运行状态进入到TIME_WAITING状态

notify()

Wakes up a single thread that is waiting on this object's monitor

唤醒一个正在等待这个对象监听器的线程

notifyAll()

Wakes up all threads that are waiting on this object's monitor

唤醒所有的在等待这个对象监听器的线程

下面是java中一个经典的通过wait()和notifyAll()方法实现的生产者消费者模型。可以加强自己对这几个方法的理解

生产者:

public class Producer implements Runnable {

   private Queue<String> bags;

   private int size;

   public Producer(Queue<String> queue, int size) {
      this.bags = queue;
      this.size = size;
   }

   @Override
   public void run() {
      int i=0;
      while (true) {
         i++;
         synchronized (bags) {
            while (size == bags.size()) {
               System.out.println("bags已经满了");
               //TODO 当队列满了,生产者阻塞
               try {
                  bags.wait();
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
               try {
                  Thread.sleep(1000);
                  bags.add("bag" + i);
                  System.out.println("生产者生产了一个bag"+i );
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
               //唤醒消费者
               bags.notifyAll();

         }
      }


   }
}

消费者:
 

public class Consumer implements Runnable {
	private Queue<String> bags;

	private int size;


	public Consumer(Queue<String> bags, int size) {
		this.bags = bags;
		this.size = size;
	}

	@Override
	public void run() {

		while (true){
			synchronized (bags){
				while (bags.isEmpty()){
					System.out.println("bags已经空了");
					try {
						bags.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				String bag = bags.remove();
				System.out.println("消费者消费了一条数据"+ bag);
				bags.notifyAll();

			}
		}

	}
}

通过一个main函数来启动生产者和消费者

public class WaitNotifyDemo {

	public static void main(String[] args) {

		Queue<String> queue = new LinkedList<>();
		int size = 10;

		Producer producer = new Producer(queue,size);
		Consumer consumer = new Consumer(queue,size);

		Thread t1 = new Thread(producer);
		Thread t2 = new Thread(consumer);

		t1.start();
		t2.start();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值