java复习笔记————线程小总结

线程的定义

  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个主线程。

  • 系统资源分配给进程,同一进程的所有线程共享该进程的所有资源。

  • 线程是指进程内的一个执行单元,也是进程内的可调度实体。

多线程的定义

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,

也就是说允许单个程序创建多个并行执行的线程来完成各自的任务

多线程的示例图

在这里插入图片描述

一个线程的生命周期

在这里插入图片描述

多线程的优点
  • Java支持编写多线程的程序;
  • 多线程最大好处在于可以同时并发执行多个任务;
  • 多线程可以最大限度地减低CPU的闲置时间,从而提高CPU的利用率
多线程的缺点
  • 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
  • 多线程需要协调和管理,所以需要CPU时间跟踪线程;
  • 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
  • 线程太多会导致控制太复杂,最终可能造成很多Bug。

线程的三种创建方法

1.继承Thread

// 继承 Thread 类  创建一个线程
class Thread_01 extends Thread {
	
	private Thread t;
	private String t_name;
	
	public Thread_01( String name ) {

		t_name = name;
		
		System.out.println("创建线程:" + t_name );
	}
	
	@Override
	public void run() {

		System.out.println("  开始运行:" + t_name );
		
		try {
			
			for ( int i = 5; i > 0; i-- ) {
				
				System.out.println("    线程 " + t_name + "---" + i );
				
				Thread.sleep(50);
			}
			
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
		
		System.out.println("  运行结束:" + t_name );
	}
	
	//封装下start()方法,不封装也可以直接调用
	public void start_Thread_01() {
		
		System.out.println(" 开始一个线程:" + t_name );
		
		if ( t == null ) {
			
			t = new Thread(this, t_name);
			
			t.start();
		}
	}
}


public class Code_002 {

	public static void main(String[] args) {
		
		Thread_01 r1 = new Thread_01(" No.1 ");
		
		r1.start_Thread_01();
		
		
		Thread_01 r2 = new Thread_01(" No.2 ");
		
		r2.start_Thread_01();
		
	}
}

2.实现Runnable接口
// 实现 Runnalbe 接口 创建线程
class Runnable_01 implements Runnable {

	private Thread t;
	private String t_name;
	
	public Runnable_01( String name ) {

		t_name = name;
		
		System.out.println(" 创建线程:" + t_name );
	}
	
	@Override
	public void run() {

		System.out.println("  开始运行:" + t_name );
		
		try {
			
			for ( int i = 5; i > 0; i-- ) {
				
				System.out.println("    线程 " + t_name + "---" + i );
				
				Thread.sleep(50);
			}
			
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
		
		System.out.println("  运行结束:" + t_name );
	}
	
//	public void start() {
	public void start_Runnable_01() {
		
		System.out.println(" 开始一个线程:" + t_name );
		
		if ( t == null ) {
			
			t = new Thread(this, t_name);
			
			t.start();
		}
	}
}


public class Code_001 {

	public static void main(String[] args) {
		
		Runnable_01 r1 = new Runnable_01(" No.1 ");
		
		r1.start_Runnable_01();
		
		
		Runnable_01 r2 = new Runnable_01(" No.2 ");
		
		r2.start_Runnable_01();
		
	}
}

3. Callable + Future 接口


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

// 实现 Callable + Future 接口 创建一个线程
class Callable_01 implements Callable<Integer> {

	@Override
	public Integer call() throws Exception {

		int i = 0;
		
		while ( i < 7 ) {
			
			System.out.println( Thread.currentThread().getName() + ": " + i );
			
			i++;
		}
		
		return i;
	}
	
}


public class Code_003 {

	public static void main(String[] args) {
		
		Callable_01 c1 = new Callable_01();
		
		FutureTask<Integer> f1 = new FutureTask<Integer>(c1);
	
		for ( int i = 0; i < 10; i++ ) {
			
			System.out.println( Thread.currentThread().getName() + ": " + i );
			
			if ( i == 7 ) {
				
				new Thread(f1, "有返回值的线程——call()").start();
			}
		}
		try {
			
			System.out.println(" 有返回值的线程返回的数值:" + f1.get() );
			
		} catch (Exception e) {

			e.printStackTrace();
		}
	}
}

使用匿名的内部类创建进程

使用 Thread 实现匿名内部类和 Runnable 实现匿名接口
//		匿名内部类
Thread t1=new Thread() {
			public void run() {
				int i;
				for (i = 15; i >0; i--) {
					System.out.println("小明正在修改策划,需要"+i+"秒");
					try {
						Thread.sleep(1000);//sleep函数睡眠
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}	
				if(i==0) {
					System.out.println("小明修改策划成功!!!");
				}
				
			}
		};
		
		t1.start();	
		
//		匿名内部类 ,匿名对象
		new Thread(
				new Runnable(){
					int m=11119999;
					public void run(){
						System.out.println("匿名内部类,匿名对象,m="+m);
					}
				}		
		).start();
创建线程的三种方式的对比
  • 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  • 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程

Thread类中的常用方法:

在这里插入图片描述

在这里插入图片描述
下面给出两个示例

//两个线程分别打印奇偶交替输出
public class PrinterRunnable implements Runnable {
	private int x=100;
	@Override
	public void run() {
		for(int i=0;i<100&&x>1;){
			synchronized(this) {
					if(Thread.currentThread().getName().equals("线程1")&&x%2!=0) {
						System.out.println(Thread.currentThread().getName()+" x="+x);
						x--;
						i++;
					}
					if(Thread.currentThread().getName().equals("线程2")&&x%2==0) {
						System.out.println(Thread.currentThread().getName()+" x="+x);
						x--;
						i++;
					}
				};
		}

	}
	
	public static void main(String[] args) {
		PrinterRunnable pr1=new PrinterRunnable();
		Thread t1=new Thread(pr1,"线程1");
		Thread t2=new Thread(pr1,"线程2");
		t1.start();
		t2.start();
	}

}

在终端的结果

在这里插入图片描述

下个例子涉及到join()、sleep()

public class JoinTest implements Runnable {

	@Override
	public void run() {
			
			for (int i = 0; i < 1000; i++) {
				System.out.println("小华正在打LOL");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		
	}

}
public class ThreadTest {
	public static void main(String[] args) {//
		JoinTest j1=new JoinTest();
		Thread t3=new Thread(j1,"线程1");	
//		匿名内部类创建线程
		Thread t4=new Thread() {
			public void run() {
				int i;
				for (i = 15; i >0; i--) {
					System.out.println("小明正在赶策划,需要"+i+"秒");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}	
				if(i==0) {
					System.out.println("小明赶策划成功!!!");
				}
				
			}
		};
		
		t4.start();		
		try {
			t4.join();

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		t3.start();
	}
}

在终端的显示

在这里插入图片描述

同步(synchronized)
一个线程访问同步方法(代码块)
class Test {
	
	// 同步代码块
	public void fun_01() {
		synchronized (this) {
			
			try {
				
				for ( int i = 0; i < 5; i++ ) {
					
					Thread.sleep(200);
					System.out.println( Thread.currentThread().getName() + " - " + " 同步方法_01 " + i );
				}
			} catch (Exception e) {
				
				e.printStackTrace();
			}
		}
	}
	
	// 非同步代码块
	public void fun_02() {
			
		try {
			
			for ( int i = 0; i < 5; i++ ) {
				
				Thread.sleep(200);
				System.out.println( Thread.currentThread().getName() + " - " + " 非同步方法 _02 " + i );
			}
		} catch (Exception e) {
			
			e.printStackTrace();
		}
	}
	
	// 同步代码块
	public void fun_03() {
		synchronized (this) {
			
			try {
				
				for ( int i = 0; i < 5; i++ ) {
					
					Thread.sleep(200);
					System.out.println( Thread.currentThread().getName() + " - " + " 同步方法_03 " + i );
				}
			} catch (Exception e) {
				
				e.printStackTrace();
			}
		}
	}
	
	
	// 同步方法
	public synchronized void fun_syn() {
		
	}
}

public class Code_001 {

	public static void main(String[] args) {
		
		Test test = new Test();
		
		Thread t1 = new Thread(
				
				new Runnable() {
					
					@Override
					public void run() {
						
						test.fun_01();
					}
				}, " 线程-t1 "
			);
		
		Thread t2 = new Thread(
				
				new Runnable() {
					
					@Override
					public void run() {
						
						test.fun_03();
					}
				}, " 线程-t2 "
			);
		
		t1.start();
		t2.start();
		
		/*
		 * 基本原则:
		 * 
		 * 	1. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个同步方法(代码块)的访问将被阻塞
		 *
		 * 	2. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个非同步方法(代码块)的访问仍然可以
		 *
		 *	3. 当一个线程访问“某对象”的同步方法(代码块)时,其他线程对“这个对象”的这个其他同步方法(代码块)的访问将被阻塞
		 *  
		 * 
		 */
	}
}

第三种情况的运行情况如下

在这里插入图片描述

对象锁(实例锁),全局锁
/*
 * 类内的方法,均为——同步方法
 * 
 */
class Test_01 {
	
	// 实例方法
	public synchronized void fun_01() {
		
		try {
			
			for ( int i = 0; i < 5; i++ ) {
				
				Thread.sleep(200);
				System.out.println( Thread.currentThread().getName() + " - " + " fun_01 " + i );
			}
		} catch (Exception e) {

			e.printStackTrace();
		}
	}
	// 实例方法
	public synchronized void fun_02() {
		
		try {
			
			for ( int i = 0; i < 5; i++ ) {
				
				Thread.sleep(200);
				System.out.println( Thread.currentThread().getName() + " - " + " fun_02 " + i );
			}
		} catch (Exception e) {

			e.printStackTrace();
		}
	}
	
	// 静态方法(类方法)
	public static synchronized void fun_03() {
		
		try {
			
			for ( int i = 0; i < 5; i++ ) {
				
				Thread.sleep(200);
				System.out.println( Thread.currentThread().getName() + " - " + " static_fun_03 " + i );
			}
		} catch (Exception e) {

			e.printStackTrace();
		}
	}
	// 静态方法(类方法)
	public static synchronized void fun_04() {
		
		try {
			
			for ( int i = 0; i < 5; i++ ) {
				
				Thread.sleep(200);
				System.out.println( Thread.currentThread().getName() + " - " + " static_fun_04 " + i );
			}
		} catch (Exception e) {

			e.printStackTrace();
		}
	}
}



public class Code_002 {

	public static void main(String[] args) {
		
		Test_01 tA = new Test_01();
		Test_01 tB = new Test_01();
		
		/*
		 * 实例锁 —— 对象锁
		 * 
		 * 	锁的是同一个对象 tA,虽然调用的是不同的 同步方法 01 和 02 
		 * 
		 * 	但依然会进行同步执行(原因基本规则三)
		 * 
		 */
//		Thread t1 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
//						tA.fun_01();
//					}
//				}, " 线程-t1 "
//			);
//		
//		Thread t2 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
//						tA.fun_02();
//					}
//				}, " 线程-t2 "
//			);
//		
//		t1.start();
//		t2.start();
		
		
		/*
		 * 实例锁 —— 对象锁
		 * 
		 * 	锁的是两个对象 tA、tB,虽然调用的是相同的 同步方法 01
		 * 
		 * 	但不会进行同步执行(原因基本规则一)
		 * 
		 */
//		Thread t1 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
//						tA.fun_01();
//					}
//				}, " 线程-t1 "
//			);
//		
//		Thread t2 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
//						tB.fun_01();
//					}
//				}, " 线程-t2 "
//			);
//		
//		t1.start();
//		t2.start();
		
		
		
		/*
		 * 全局锁 —— 类型锁
		 * 
		 * 	锁的是一整个类型,所有的对象 共用一个静态方法(类方法)
		 * 	进一步推断,所有对象调用 同步方法03 或 04 时,在使用类里面的同一把锁
		 * 
		 * 	但依然会进行同步执行(原因基本规则一)
		 */
//		Thread t1 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
//						tA.fun_03();
//						Test_01.fun_03();
//					}
//				}, " 线程-t1 "
//			);
//		
//		Thread t2 = new Thread(
//				
//				new Runnable() {
//					
//					@Override
//					public void run() {
//						
						tB.fun_03();
//						tA.fun_04();
						Test_01.fun_04();
						Test_01.fun_03();
//					}
//				}, " 线程-t2 "
//			);
//		
//		t1.start();
//		t2.start();
		
		
		
		/*
		 * 实例锁 —— 对象锁
		 * 全局锁 —— 类型锁
		 * 
		 * 	线程1 持有对象tA的实例锁,线程2 持有类型Test_01的全局锁,
		 * 	两个线程分别使用两把不一样的锁
		 * 
		 * 	因此,不会进行同步执行
		 * 
		 */
		Thread t1 = new Thread(
				
				new Runnable() {
					
					@Override
					public void run() {
						
						tA.fun_01();
					}
				}, " 线程-t1 "
			);
		
		Thread t2 = new Thread(
				
				new Runnable() {
					
					@Override
					public void run() {
						
						Test_01.fun_03();
					}
				}, " 线程-t2 "
			);
		
		t1.start();
		t2.start();
	}
}

分别调用对象锁和全局锁的结果

在这里插入图片描述

同步锁中wait()和notify()的使用

下面有两种情况情况一是,不管有没有notify都会自己解锁,情况2是必须等待唤醒才能解锁,具体的分析在代码里

情况1

  class Thread_03 extends Thread {
	
	public Thread_03( String name ){
		
		super(name);
	}
	
	@Override
	public void run() {

		synchronized (this) {
			
			System.out.println( Thread.currentThread().getName() + " 开始执行! ");
			
			System.out.println( Thread.currentThread().getName() + " 进行唤醒!");
			
			//notify();
			/*
			 * 此处 无论有没有  notify() 方法,外面的主线程依然会正常执行结束
			 * 
			 * 分析原因:
			 *	1. test线程执行完 run() 之后,test线程正常结束。
			 *	2. 那么执行 “ test.wait() ”这句代码的线程(main线程)退出等待队列,相当于唤醒。
			 * 	3. 然后 main线程获取同步锁,进入就绪进而执行
			 * 
			 * 
			 * 核心关键点:
			 * 
			 * 		当“某线程”正常结束之后,会使以“这个线程作为对象”运行的wait()的线程(main线程)等待状态结束。
			 * 
			 * 	
			 * 	test.wait() 在代码中的实际作用:
			 * 
			 * 		在当前线程(main线程)中,以 test线程作为对象,调用wait()方法
			 */
			
			try {
				
				Thread.sleep(2000);
				
			} catch (Exception e) {

				e.printStackTrace();
			}
			
			System.out.println( Thread.currentThread().getName() + " 执行结束! ");
			
		}
	}
}

public class Code_003 {

	public static void main(String[] args) {
		
		Thread_03 test = new Thread_03(" 线程 test ");
		
		synchronized ( test ) {
			
			try {
				
				System.out.println( Thread.currentThread().getName() + " 启动 【线程 test】");
				test.start();
				
				System.out.println( Thread.currentThread().getName() + " 即将进行 wait() ");
				test.wait(); // 是 main线程在执行 这行代码,因此 main线程进入等待状态
				
				System.out.println( Thread.currentThread().getName() + " wait() 执行完毕 ");
				
			} catch (Exception e) {

				e.printStackTrace();
			}
		}
	}
}

情况二

class Thread_04 extends Thread {
	
	public Thread_04( String name ) {
		
		super(name);
	}
	
	@Override
	public void run() {

		synchronized ( Code_004.lockstr ) {
			
			System.out.println( Thread.currentThread().getName() + " 开始执行! ");
			
			System.out.println( Thread.currentThread().getName() + " 进行唤醒!");
			
//			Code_004.lockstr.notify();
			/*
			 * 如果这里没有唤醒方法,则test线程执行结束之后,
			 * 调用“ Code_004.lockstr.wait(); ”代码的线程(main线程)无法被唤醒,那么程序就一直卡在这
			 * 
			 * 
			 * 核心关键点:
			 * 
			 * 		Code_004.lockstr是一个对象,但不是一个线程作为对象!
			 * 
			 * 
			 * Code_004.lockstr.wait() 在代码中的实际作用:
			 * 
			 * 		在当前线程(main线程)中,以Code_004.lockstr对象,调用wait()方法
			 */
			
			try {
				
				sleep(1000);
				
			} catch (Exception e) {

				e.printStackTrace();
			}
			
			System.out.println( Thread.currentThread().getName() + " 执行结束! ");
			
		}
	}
}


public class Code_004 {

	public static String lockstr = "lock";

	public static void main(String[] args) {
		
		Thread_04 test = new Thread_04(" 线程 test ");
		
		synchronized ( Code_004.lockstr ) {
			
			try {
				
				System.out.println( Thread.currentThread().getName() + " 启动 【线程 test】");
				test.start();
				
				System.out.println( Thread.currentThread().getName() + " 即将进行 wait() ");
				Code_004.lockstr.wait(); // 是 main线程在执行 这行代码,因此 main线程进入等待状态
				
				System.out.println( Thread.currentThread().getName() + " wait() 执行完毕 ");
				
			} catch (Exception e) {

				e.printStackTrace();
			}
		}
	}
}

生产着和消费者模型
// 仓库
class Depot {
	
	private int capacity; // 容量 
	private int size; // 实际存放的数量
	
	public Depot( int num ) {

		this.capacity = num;
		this.size = 0;
	}
	
	// 生产行为
	public synchronized void produce( int num ) throws InterruptedException {
		
		// num 表示需要生产的数量,这个数量有可能比实际剩余的容量多
		// left 表示即将被生产的数量,这个数量有可能比实际剩余的容量多
		int left = num;
		
		while ( left > 0 ) {
			
			// 当仓库满了,则需要等待 “消费者” 从仓库 消费 商品(为了腾出位置放新的商品)
			while ( size >= capacity ) {
				
				wait();
			}
			
			// “实际生产的数量” —— 实际存放到仓库里面的商品数量
			int actual_produce = 0;
			/*
			 * 如果 库存+想要生产的数量 大于 总容量,
			 * 则 实际生产的数量 = 总容量 - 库存
			 * 否则  实际生产的数量 = 想要生产的数量
			 */
			actual_produce = ((size + left) > capacity) ? (capacity-size) : left;
			
			// 放入仓库,size 增加 actual
			size += actual_produce;
			
			// 即将放入的数量会随着放入仓库成功的行为而减少
			left -= actual_produce;
			
			System.out.println(Thread.currentThread().getName() + " 需要生产:" + num + 
					"  实际放到仓库:" + actual_produce + 
					"  仓库现有库存:" + size + 
					"  还需要生产:" + left );
			
			// 唤醒 消费者 进行 商品消费
			notifyAll();
		}
	}
	
	// 消费行为
	public synchronized void consume( int num ) throws InterruptedException {
		
		// num 表示需要消费的数量,这个数量有可能比实际库存多
		// right 表示即将被消费的数量,这个数量有可能比实际库存多
		int right = num;
		
		while ( right > 0 ) {
			
			// 当仓库空了,则需要等待 “生产者” 往仓库 生产 商品(为了能有可以消费的商品)
			while ( size <= 0 ) {
				
				wait();
			}
			
			// “实际消费的数量” —— 实际从仓库里面取出的商品数量
			int actual_consume = 0;
			/*
			 * 如果 库存 少于 需要消费的数量,
			 * 则 实际消费的数量 = 库存
			 * 否则  实际消费的数量 = 想要消费的数量
			 */
			actual_consume = (size < right) ? size : right ;
			
			// 仓库取出,size 减少 actual
			size -= actual_consume;
			
			// 即将取出的数量会随着仓库取出成功的行为而减少
			right -= actual_consume;
			
			System.out.println(Thread.currentThread().getName() + " 需要消费:" + num + 
					"  仓库实际取出:" + actual_consume + 
					"  仓库现有库存:" + size +
					"  还需要消费:" + right );
			
			// 唤醒 生产者 进行 商品生产
			notifyAll();
		}
	}
}

// 生产者
class Producer {
	
	// 生产者 操作的仓库
	private Depot depot;
	
	public Producer( Depot d ) {

		this.depot = d;
	}
	
	// 生产商品 —— 创建一个线程往仓库里面放入商品
	public void fun_produce( int num ) {
		
		new Thread() {
			
			@Override
			public void run() {

				try {
					
					depot.produce(num);
					
				} catch (Exception e) {
					
					e.printStackTrace();
				}
			}
		}.start();
	}
}

// 消费者
class Consumer {
	
	// 消费者 操作的仓库
	private Depot depot;
	
	public Consumer( Depot d ) {

		this.depot = d;
	}
	
	// 消费商品 —— 创建一个线程从仓库里面取出商品
	public void fun_Consumer( int num ) {
		
		new Thread() {
			
			@Override
			public void run() {

				try {
					
					depot.consume(num);
					
				} catch (Exception e) {
					
					e.printStackTrace();
				}
			}
		}.start();
	}
}


public class Code_001 {

	public static void main(String[] args) {
		
		// 创建仓库 d1
		Depot d1 = new Depot(10);
		
		// 生产者 p1
		Producer p1 = new Producer(d1);
		// 消费者 c1
		Consumer c1 = new Consumer(d1);
		
		
		// 情况1
//		p1.fun_produce(7);
//		p1.fun_produce(6);
//		c1.fun_Consumer(1);
//		c1.fun_Consumer(2);
		
		// 情况2 特殊,没有商品进行消费行为
//		c1.fun_Consumer(7);
		
		// 情况3
		p1.fun_produce(2);
		c1.fun_Consumer(7);
		p1.fun_produce(1);
		p1.fun_produce(4);
	}
}

第三种情况的结果
前两种情况可以把代码copy下来自己在本地运行一下
在这里插入图片描述

互斥锁的基本用法

之前在用同步锁是通过调用wait函数进行等待,然后调用notifyAll进行全部的唤醒,现在我们就使用
互斥锁来实现对特定的对象进行解锁,这样更加能够满足需求

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Code_003 {

	// 创建一个互斥锁
	public static Lock lock = new ReentrantLock();
	
	// 利用锁 绑定一个条件
	public static Condition condition = lock.newCondition();
	
	// 线程类
	static class Thread_03 extends Thread {
		
		@Override
		public void run() {

			// 加锁
			lock.lock();
			try {
				
				System.out.println(this.getName() + " 进行唤醒... ");
//				notify();
				condition.signal();
				
			} finally {
				
				// 解锁
				lock.unlock();
			}
		}
	}
	
	
	public static void main(String[] args) throws InterruptedException {
		
		Thread_03 t3 = new Thread_03();
		t3.setName(" 线程_03 ");
		
		// 加锁
		lock.lock();
		
		System.out.println(Thread.currentThread().getName() + " 启动  线程_03 ");
		t3.start();
		
		System.out.println(Thread.currentThread().getName() + " 进行 等待... ");
//		t3.wait();
		condition.await();
		
		System.out.println(Thread.currentThread().getName() + " 执行 结束!! ");
		
		// 解锁
		lock.unlock();
	}
}

在控制台的结果
在这里插入图片描述

基于生产者和消费者模型使用互斥锁
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 简版,不考虑仓库容量,操作行为可以导致负数结果
 * 
 * 完整版,需要考虑仓库容量,操作结构不能为负数
 * 
 */

class Depot {
	
	private int capacity; // 仓库的容量 - max
	private int size; // 实际存放数量
	
	private Lock lock; // 互斥锁
	
	private Condition full; // 放满
	private Condition empty; // 取空
	
	public Depot( int num ) {

		this.capacity = num;
		this.size = 0;
		
		this.lock = new ReentrantLock();
		
		this.full = lock.newCondition();
		this.empty = lock.newCondition();
	}
	
	// 生产行为
	public void produce( int num ) {
		
		// 进方法的第一行代码加锁(第一件事)
		lock.lock();
		
		try {
			
			// 即将生产的商品数量
			int left = num;
			
			while ( left > 0 ) {
				
				// 如果现有库存满了,需要 “等待” 消费者取仓库取出商品,腾出位置放新的商品
				while ( size >= capacity ) {
					
					full.await();
				}
				
				// 如果需要放入的数量 + 库存  大于  容量,那么只能放入 容量 - 库存;否则 可以放入需要放入的数量
				// 实际放入的商品数量
				int actual_produce = ( (size+left) > capacity ) ? (capacity-size) : left;
				
				// 库存增加
				size += actual_produce;
				// 即将要放入的数量减少
				left -= actual_produce;
				
				System.out.println(Thread.currentThread().getName() + 
						" 需要生产:" + num + 
						" 实际放入仓库:" + actual_produce +
						" 仓库现有库存:" + size +
						" 还需要放入:" + left);
				
				// 唤醒 消费者
				empty.signal();
			}
			
		} catch ( InterruptedException e ) {

			e.printStackTrace();
			
		} finally {
			
			// 解锁
			lock.unlock();
		}
	}
	
	// 消费行为
	public void consume( int num ) {
		
		// 加锁
		lock.lock();
		
		try {
			
			// 即将消费的商品数量
			int right = num;
			
			while ( right > 0 ) {
				
				// 如果现有库存空了,需要 “等待” 生产者往仓库放入商品,才能继续取出商品
				while ( size <= 0 ) {
					
					empty.await();
				}
				
				// 如果需要取出的数量  大于  库存,那么只能取出 库存;否则 可以取出需要取出的数量
				// 实际取出的商品数量
				int actual_consume = ( right > size ) ? size : right;
				
				// 库存减少
				size -= actual_consume;
				// 即将要取出的数量减少
				right -= actual_consume;
				
				System.out.println(Thread.currentThread().getName() + 
						" 需要消费:" + num + 
						" 实际取出仓库:" + actual_consume +
						" 仓库现有库存:" + size +
						" 还需要取出:" + right);
				
				// 唤醒 生产者
				full.signal();
			}
			
		} catch ( InterruptedException e ) {

			e.printStackTrace();
			
		} finally {
			
			// 解锁
			lock.unlock();
		}
	}
}


// 生产者
class Producer {
	
	private Depot depot;
	
	public Producer( Depot d ) {

		this.depot = d;
	}
	
	public void fun_produce( int num ) {
		
		new Thread() {
			
			public void run() {
				
				try {
					
					depot.produce(num);
					
				} catch (Exception e) {

					e.printStackTrace();
				}	
			}
		}.start();
	}
}

// 消费者
class Consumer {
	
	private Depot depot;
	
	public Consumer( Depot d ) {

		this.depot = d;
	}
	
	public void fun_consume( int num ) {
		
		new Thread() {
			
			public void run() {
				
				depot.consume(num);
			}
		}.start();
	}
}


public class Code_001 {

	public static void main(String[] args) {
		
		// 创建仓库 d1
		Depot d1 = new Depot(10);
		
		// 生产者 p1
		Producer p1 = new Producer(d1);
		// 消费者 c1
		Consumer c1 = new Consumer(d1);
		
		
		p1.fun_produce(12);
//		p1.fun_produce(6);
		c1.fun_consume(1);
		c1.fun_consume(3);
		
	}
}

在控制台的结果
在这里插入图片描述

线程池(★★★★★)
线程池的访问流程

在这里插入图片描述

Executors.newFixedThreadPool():固定大小的线程池

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Thread_01 extends Thread{
	
	@Override
	public void run() {
		
		System.out.println( Thread.currentThread().getName() + " 执行中...");
	}
}



public class Code_001 {

	public static void main(String[] args) {
		
		/*
		 *	固定大小的线程池
		 *
		 *	可以指定线程池的大小(可容纳的线程的数量),这种线程池的 corePoolSize 等于  maximumPoolSize
		 *		在线程池的运行过程中,线程的数量不会变化;
		 *		有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则进入队列等待
		 *
		 *	任务队列的类型是:LinkedBlockingQueue —— 无界
		 *
		 */
		ExecutorService pool = Executors.newFixedThreadPool(3);
		
		
		// 创建线程
		Thread t1 = new Thread_01();
		Thread t2 = new Thread_01();
		Thread t3 = new Thread_01();
		Thread t4 = new Thread_01();
		Thread t5 = new Thread_01();
		Thread t6 = new Thread_01();
		Thread t7 = new Thread_01();
		Thread t8 = new Thread_01();
		Thread t9 = new Thread_01();
		
		
		// 将线程放入线程池中进行执行
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
		pool.execute(t6);
		pool.execute(t7);
		pool.execute(t8);
		pool.execute(t9);
		
		// 关闭线程池
		pool.shutdown();
	}
}

在控制台的结果
在这里插入图片描述

Executors.newSingleThreadExecutor():单个线程的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Thread_02 extends Thread{
	
	@Override
	public void run() {
		
		System.out.println( Thread.currentThread().getName() + " 执行中...");
	}
}


public class Code_002 {

	public static void main(String[] args) {
		
		/*
		 *	单个线程的线程池
		 *	
		 *	只有一个线程的线程池( corePoolSize 等于  maximumPoolSize 等于 1 )
		 *		在线程池的运行过程中,线程的数量不会变化;
		 *		有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则进入队列等待
		 *
		 *	任务队列的类型是:LinkedBlockingQueue —— 无界
		 *
		 *	意味着所有任务必须严格按照 “ 先进先出 ” 的顺序执行
		 */
		ExecutorService pool = Executors.newSingleThreadExecutor();
		
		// 创建线程
		Thread t1 = new Thread_02();
		Thread t2 = new Thread_02();
		Thread t3 = new Thread_02();
		Thread t4 = new Thread_02();
		Thread t5 = new Thread_02();
		Thread t6 = new Thread_02();
		Thread t7 = new Thread_02();
		Thread t8 = new Thread_02();
		Thread t9 = new Thread_02();
		
		// 将线程放入线程池中进行执行
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
		pool.execute(t6);
		pool.execute(t7);
		pool.execute(t8);
		pool.execute(t9);
		
		// 关闭线程池
		pool.shutdown();
	}
}

在控制台的结果
在这里插入图片描述

Executors.newCachedThreadPool():缓存线程池


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Thread_03 extends Thread{
	
	@Override
	public void run() {
		
		System.out.println( Thread.currentThread().getName() + " 执行中...");
	}
}

public class Code_003 {

public static void main(String[] args) {
		
		/*
		 *	缓存线程池
		 *	
		 *	不长期持有固定线程,有新任务就在线程池中增加一个新线程,当该线程执行完任务之后,保留一段时间再销毁
		 *		corePoolSize 等于  0
		 *		maximumPoolSize 等于 随机情况,没有固定值
		 *		KeepAliveTime 默认 60 秒
		 *	
		 *		在线程池的运行过程中,线程的数量会变化;
		 *		有新任务来时,有空闲线程,则立即执行;如果没有空闲线程,则创建新的线程;
		 *		线程执行完任务之后,空闲等待时间为60秒(默认),时间到了就释放该线程。
		 *
		 *	任务队列的类型是:SynchronousQueue —— 立即执行
		 *
		 */
		ExecutorService pool = Executors.newCachedThreadPool();
		
		// 创建线程
		Thread t1 = new Thread_03();
		Thread t2 = new Thread_03();
		Thread t3 = new Thread_03();
		Thread t4 = new Thread_03();
		Thread t5 = new Thread_03();
		Thread t6 = new Thread_03();
		Thread t7 = new Thread_03();
		Thread t8 = new Thread_03();
		Thread t9 = new Thread_03();
		
		// 将线程放入线程池中进行执行
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t4);
		pool.execute(t5);
		pool.execute(t6);
		pool.execute(t7);
		pool.execute(t8);
		pool.execute(t9);
		
		// 关闭线程池
		pool.shutdown();
	}
}

在控制台的结果
在这里插入图片描述

ScheduledThreadPoolExecutor(1):定时执行的线程池

package 多线程.Day_04_16_Code.Day_04_16_Code;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Code_004 {

	public static void main(String[] args) {
		
		/*
		 * 	定时执行的线程池
		 * 
		 * 	在设置时间规则之后,可以一直执行下去
		 * 
		 * 	
		 * 	
		 */
		ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
		
		pool.scheduleAtFixedRate(
				new Runnable() {
					
					@Override
					public void run() {
						System.out.println( Thread.currentThread().getName() + " 执行中...");
					}
				}
				, 0, 2, TimeUnit.SECONDS);
		
	}
}

执行的结果,每两秒执行线程一次
在这里插入图片描述
接下来的部分会接着整理,继续努力

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值