线程5

定时任务
public class Timer extends Object
线程调度任务以供将来在后台线程中执行的功能。 任务可以安排一次执行,或定期重复执行。
在这里插入图片描述

public static void main(String[] args) throws ParseException {
		// 创建定时器
		Timer  timer = new Timer("timer1");
		// 使用定时器执行计划任务
		timer.schedule(new TimerTask() {
			//需要执行的任务
			@Override
			public void run() {
				 System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
				
			}
		}, new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2019-11-28 19:56:12"), 1000);
	}
public static void main(String[] args) throws ParseException {
		// 创建定时器
		Timer  timer = new Timer("timer1");
		// 使用定时器执行计划任务
		timer.schedule(new TimerTask() {
			//需要执行的任务
			@Override
			public void run() {
				 System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
				
			}
		}, //new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2019-11-28 19:56:12"), 1000
		5000,1000);
		
	}

线程间的通信

//实现两个线程的交替执行
	/*线程间的通信
	 * wait/wait(long timeout))
	 * notify()  如果由多个线程  则随机的唤醒某一个线程
	 * notifyAll()唤醒所有处于等待的线程
	 */

	public static void main(String[] args) {
		ThreadNotify t = new ThreadNotify();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
					t.print2();
				}
				
				
			}
		}).start() ;
		new Thread() {
			@Override
			public void run() {
				while(true) {
					
					t.print1();
				}
				 
			}
		}.start();
	
	}
	
	
	public synchronized void print1() {
		notifyAll();
		System.out.print("中");
		System.out.print("北");
		System.out.print("大");
		System.out.print("学");
		System.out.println();
		try {
			wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public  synchronized void print2() {
		notifyAll();
		System.out.print("蓝");
		System.out.print("桥");
		System.out.print("软");
		System.out.print("件");
		System.out.print("学");
		System.out.print("院");
		System.out.println();
		try {
			wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

互斥锁
三个或三个以上间的线程通信
◦多个线程通信的问题
◦notify()方法是随机唤醒一个线程
◦notifyAll()方法是唤醒所有线程
◦JDK5之前无法唤醒指定的一个线程
◦如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件
JDK1.5的新特性互斥锁
所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作。
Lock和synchronized机制的主要区别:
synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出现在同一个块结构中, 以及以更自由的顺序释放锁提供了可能.
• 1.同步
◦使用ReentrantLock类的lock()和unlock()方法进行同步
•2.通信
◦使用ReentrantLock类的newCondition()方法可以获取Condition对象
◦需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
◦不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

public class ThreadNotify {

	public static void main(String[] args) {
		ThreadNotify t = new ThreadNotify();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
					t.print2();
				}
				
				
			}
		}).start() ;
		new Thread() {
			@Override
			public void run() {
				while(true) {
					
					t.print1();
				}
				 
			}
		}.start();
		new Thread() {
			@Override
			public void run() {
				while(true) {
					
					t.print3();
				}
				 
			}
		}.start();
	
	}
	
	ReentrantLock lock = new ReentrantLock();//锁对象
	Condition c1 = lock.newCondition();//通信环境
	Condition c2 = lock.newCondition();
	Condition c3 = lock.newCondition();
	int flag = 1 ;
	public void print1() {
		lock.lock();//对当前代码上锁
		if(flag == 1) {
			
			System.out.print("中");
			System.out.print("北");
			System.out.print("大");
			System.out.print("学");
			System.out.println();
			try {
				c1.await();
				flag = 2;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(flag == 2) {
			c2.signal();
		}
		lock.unlock();
		
		
	}
	public   void print2() {
		lock.lock();
		if(flag == 2) {
			System.out.print("蓝");
			System.out.print("桥");
			System.out.print("软");
			System.out.print("件");
			System.out.print("学");
			System.out.print("院");
			System.out.println();
			try {
				c2.await();
				flag = 3;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
		if(flag == 3) {
			c3.signal();
		}
		lock.unlock();
	}
	public  void print3() {
		lock.lock();
		if(flag == 3) {
			System.out.print("山");
			System.out.print("西");
			System.out.print("太");
			System.out.print("原");
			System.out.println();
			try {
				c3.await();
				flag = 1;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		if(flag == 1) {
			c1.signal();
		}
		lock.unlock();
		
	}
}

线程第三种创建方法 :线程池
JDK5.0新增线程创建方式
我们在传统多线程编程创建线程时,常常是创建一些Runnable对象,然后创建对应的Thread对象执行它们,但是如果程序需要并发执行大量的任务时,需要为每个任务都创建一个Thread,进行管理,这将会影响程序的执行效率,并且创建线程过多将会使系统负载过重。
在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外。
为什么引入Executor线程池框架
new Thread()的缺点
每次new Thread()耗费性能
调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。
不利于扩展,比如如定时执行、定期执行、线程中断
采用线程池的优点
重用存在的线程,减少对象创建、消亡的开销,性能佳
可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
提供定时执行、定期执行、单线程、并发数控制等功能

Executor框架
Executor框架集对线程调度进行了封装,将任务提交和任务执行解耦。它提供了线程生命周期调度的所有方法,大大简化了线程调度和同步的门槛。
在这里插入图片描述
Executor接口中之定义了一个方法execute(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类。
ExecutorService接口继承自Executor接口,它提供了更丰富的实现多线程的方法。比如,ExecutorService提供了关闭自己的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。
AbstractExecutorService:ExecutorService执行方法的默认实现
ScheduledExecutorService:一个可定时调度任务的接口
ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象Executors提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

public static void main(String[] args) {
		/*
		 *  创建ExecutorService的方式:
		 *  static ExecutorService newFixedThreadPool(int nThreads) 
			创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。  
		 */
		ExecutorService service = Executors.newFixedThreadPool(5);
		for(int i = 0 ; i < 12;i++) {
			Runnable task = new Runnable() {
				@Override
				public void run() {
				 System.out.println(Thread.currentThread().getName());	
				}
			};
			service.execute(task);
		}
		
	}
public static void main(String[] args) {
		/*
		 *  创建ExecutorService的方式:
		 *   public static ExecutorService newCachedThreadPool()创建一个可缓存的线程池,
		 *   调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,
		 *   则创建一个新线  程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。。  
		 */
		ExecutorService service = Executors.newCachedThreadPool();
		for(int i = 0 ; i < 12;i++) {
			Runnable task = new Runnable() {
				@Override
				public void run() {
				 System.out.println(Thread.currentThread().getName());	
				}
			};
			service.execute(task);
		}
		service.shutdown();
	}
public static void main(String[] args) {
		/*
		 *  创建ExecutorService的方式:  
		 */
		ExecutorService service = Executors.newSingleThreadExecutor();
		for(int i = 0 ; i < 12;i++) {
			Runnable task = new Runnable() {
				@Override
				public void run() {
				 System.out.println(Thread.currentThread().getName());	
				}
			};
			service.execute(task);
		}
		service.shutdown();
	}
public class ExecutorPoolTest {
	public static void main(String[] args) {
		/*
		 *  创建ExecutorService的方式:  
		 */
		ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
		for(int i = 0 ; i < 12;i++) {
			Runnable task = new Runnable() {
				@Override
				public void run() {
				 System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));	
				}
			};
			service.scheduleAtFixedRate(task, 3000,1000, TimeUnit.MILLISECONDS);
		}
		
	}
}

这四种方法都是用的Executors中的ThreadFactory建立的线程, 一般来说,CachedTheadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的Executor的首选,只有当这种方式会引发问题时(比如需要大量长时间面向连接的线程时),才需要考虑用FixedThreadPool。(该段话摘自《Thinking in Java》第四版)
执行Callable任务:

public class CollableTask {
	public static void main(String[] args) {
		//创建ExecutorService
		ExecutorService service = Executors.newFixedThreadPool(5);
		List<Future<String>> resList = new ArrayList<>();
		for(int i = 0 ; i < 20 ;i++) {
			Future<String> result = service.submit(new Task(i));
			resList.add(result);
		}
		
		for(Future<String> f : resList) {
			while(!f.isDone()) {}//如果任务没有完成  则等待其完成
				try {
					String done = f.get();
					System.out.println(done);
				} catch (InterruptedException | ExecutionException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}finally {
					service.shutdown();
				}
				
			
		}
		
	}
	
}

class Task implements Callable<String>{
	private int id;
	public Task(int id) {
		this.id = id;
	}
	
	@Override
	public String call() throws Exception {
		 
		return "id="+id+"***的任务被执行......"+Thread.currentThread().getName();
	}
	
}

Executor的生命周期
ExecutorService的生命周期包括三种状态:运行、关闭、终止。
创建后便进入运行状态。
当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当所有已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态,不断接收新的任务,执行新的任务,服务器端一般不需要关闭它,保持一直运行即可。
shutdownNow方法将强制终止所有运行中的任务并不再允许提交新任务

总结:
1 了解进程 线程 CPU核 并发 并行
2 线程的创建方式 :Thread Runable
3 线程的一些常用方法:run start sleep join yield
4 线程的调度方式:时间片 抢占式
同优先级 时间片
不同优先级 抢占式
5 线程的优先级: 1–10 默认5 线程的优先级:决定的线程获得CPU的几率
6 线程的生命周期:新建 就绪 运行 阻塞 死亡
7 线程同步 什么时候需要线程同步 线程同步的方式 同步锁 死锁
8 线程间的通信 互斥锁
9 线程池框架
10 线程池的生命周期

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值