(1)线程间通信问题–生产者和消费者多线程体现
1-定义:不同种类的线程间针对同一个资源的操作
2-等待唤醒机制改进该程序,让数据能够实现依次的出现
Object类提供:
-wait()--等待
-notify()--唤醒单个线程
-notifyAll()--唤醒多个线程
3-为什么这些方法不定义在Thread类种?
--这些方法的调用必须通过锁对象调用,而锁对象是任意对象,
因此,这些方法必须定义在Object类
一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。
4-等待唤醒机制的代码优化。把数据及操作都写在了资源类中,因为更符合面向对象的思想
5-Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,
相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作
更加安全和高效。
Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,
就是说必须在lock.lock()和lock.unlock之间才可以使用
Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()
(2)线程组–ThreadGroup类
1-常用方法:
--Thread类中:public final ThreadGroup getThreadGroup()-返回此线程所属的线程组
--ThreadGroup类:public final String getName()-返回此线程组的名称。
线程默认的情况下,所有的线程都属于同一个组;
--Thread.currentThread().getThreadGroup().getName() //返回main
所有的线程它默认的线程组名称:main(主线程),主线程是包含在线程组里面的
2-如何修改线程组?
1-创建新的线程组
--public ThreadGroup(String name)构造一个新线程组
2-在创建线程时,把组指定为新的线程组
--Thread(ThreadGroup group, Runnable target, String name)
(3)线程池:
1-定义:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态
等待下个对象使用
2-Executors 工厂类来产生线程池
1、创建线程池对象,控制要创建几个线程对象Callable接口
--public static ExecutorService newFixedThreadPool(int nTreads)
2、这种线程池的线程可以执行:
--Runnable对象和Callable<K>对象代表的线程--返回值
3、提交线程任务:submit/execute
--Future<?> submit(Runnable task)-提交Runnable任务执行并返回表示该任务的Future。
--<T> Future<T> submit(Callable<T> task):
Future<String> future = es.submit(new MyThreadClass());
获取返回值: String s = future.get();
--public void execute(Runnable command)
4、结束:
--shutdown():线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
--shutdownNow():线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
Callable<K>的泛型是call()方法的返回值类型
1-java.util.concurrent.Callable是一个泛型接口,只有一个call()方法
2-call()方法抛出异常Exception异常,且返回一个指定的泛型类对象
(4)匿名内部类方式使用多线程:
1-继承Thread类来实现多线程
new Thread() { }.start();
2-实现Runnable接口来实现多线程
new Thread(new Runnable(){ }){如有线程,运行这里的代码 }.start();
(5)定时器:
1-Timer类:线程的工具,用于在后台线程中安排将来执行的任务。是线程安全的,不提供实时保证
可以将任务安排为一次性执行,或者以固定间隔重复执行。
TimerTask类:一次性或重复执行的任务,实现Runnable接口
枚举TimeUnit类:提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep()
2-常用方法:
1、public Timer()-创建一个新计时器
2、public void schedule(TimerTask task,long delay)
--在指定的延迟后安排指定的任务执行
3、public void schedule(TimerTask task,long delay,long period)
--在指定的延迟之后开始,为重复的固定延迟执行安排指定的任务。
4、schedule(TimerTask task, Date time)
--计划在指定时间执行指定的任务。
5、schedule(TimerTask task, Date firstTime, long period)
--从指定时间开始,为重复的固定延迟执行安排指定的任务。
6、scheduleAtFixedRate(TimerTask task, long delay, long period)
--在指定的延迟之后开始,为重复的固定速率执行安排指定的任务。
--task--这是被调度的任务。
--delay--这是以毫秒为单位的延迟之前的任务执行。
--period--这是在连续执行任务之间的毫秒的时间。
7、public void cancel()--终止此计时器,丢弃当前计划的任何任务。
@@一般情况下,timer的schedule和scheduleAtFixedRate方法没有区别,
只在某个情况出现时会有区别--当前任务没有来得及完成下次任务又交到手上。
--schedule不受约
--scheduleAtFixedRate按时完成